diff options
| author | Philipp Krones <hello@philkrones.com> | 2024-04-04 19:52:55 +0200 |
|---|---|---|
| committer | Philipp Krones <hello@philkrones.com> | 2024-04-04 19:52:55 +0200 |
| commit | 0ae4a048c6fa9c84d169e1bba8747661099b2111 (patch) | |
| tree | 38f22313a66bf2bba76bd4b98bb8d675d71e4e72 /clippy_lints | |
| parent | 53e31dc45cecb671c664dd13685cfa9dc832b336 (diff) | |
| download | rust-0ae4a048c6fa9c84d169e1bba8747661099b2111.tar.gz rust-0ae4a048c6fa9c84d169e1bba8747661099b2111.zip | |
Merge commit '9725c4a162502a02c1c67fdca6b797fe09b2b73c' into clippy-subtree-update
Diffstat (limited to 'clippy_lints')
288 files changed, 1588 insertions, 780 deletions
diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 25606f4253e..ec28fd46111 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -95,7 +95,7 @@ impl ApproxConstant { cx, APPROX_CONSTANT, e.span, - &format!("approximate value of `{module}::consts::{}` found", &name), + format!("approximate value of `{module}::consts::{}` found", &name), None, "consider using the constant directly", ); diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index c2fa56e1360..7c88bfc97ca 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -53,9 +53,9 @@ fn check_asm_syntax( cx, lint, span, - &format!("{style} x86 assembly syntax used"), + format!("{style} x86 assembly syntax used"), None, - &format!("use {} x86 assembly syntax", !style), + format!("use {} x86 assembly syntax", !style), ); } } diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 9365fbfaed0..2003dd1fb0e 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { cx, ASSERTIONS_ON_CONSTANTS, macro_call.span, - &format!( + format!( "`{}!(true)` will be optimized out by the compiler", cx.tcx.item_name(macro_call.def_id) ), @@ -74,9 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { cx, ASSERTIONS_ON_CONSTANTS, macro_call.span, - &format!("`assert!(false{assert_arg})` should probably be replaced"), + format!("`assert!(false{assert_arg})` should probably be replaced"), None, - &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"), + format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"), ); } } diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 8e27b3ccefd..dc7f44af2b7 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -65,7 +65,7 @@ impl AssigningClones { impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { - fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) { // Do not fire the lint in macros let expn_data = assign_expr.span().ctxt().outer_expn_data(); match expn_data.kind { @@ -181,6 +181,23 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC return false; } + // If the call expression is inside an impl block that contains the method invoked by the + // call expression, we bail out to avoid suggesting something that could result in endless + // recursion. + if let Some(local_block_id) = impl_block.as_local() + && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner() + { + let impl_block_owner = block.def_id(); + if cx + .tcx + .hir() + .parent_id_iter(lhs.hir_id) + .any(|parent| parent.owner == impl_block_owner) + { + return false; + } + } + // Find the function for which we want to check that it is implemented. let provided_fn = match call.target { TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { @@ -205,14 +222,9 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC implemented_fns.contains_key(&provided_fn.def_id) } -fn suggest<'tcx>( - cx: &LateContext<'tcx>, - assign_expr: &hir::Expr<'tcx>, - lhs: &hir::Expr<'tcx>, - call: &CallCandidate<'tcx>, -) { +fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) { span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { - let mut applicability = Applicability::MachineApplicable; + let mut applicability = Applicability::Unspecified; diag.span_suggestion( assign_expr.span, @@ -263,7 +275,7 @@ impl<'tcx> CallCandidate<'tcx> { fn suggested_replacement( &self, cx: &LateContext<'tcx>, - lhs: &hir::Expr<'tcx>, + lhs: &Expr<'tcx>, applicability: &mut Applicability, ) -> String { match self.target { diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs index df00f23e37e..4a22e17463f 100644 --- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -30,7 +30,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet cx, ALLOW_ATTRIBUTES_WITHOUT_REASON, attr.span, - &format!("`{}` attribute without specifying a reason", name.as_str()), + format!("`{}` attribute without specifying a reason", name.as_str()), None, "try adding a reason at the end with `, reason = \"..\"`", ); diff --git a/clippy_lints/src/attrs/duplicated_attributes.rs b/clippy_lints/src/attrs/duplicated_attributes.rs index 3c5ac597fd5..3a8844d0754 100644 --- a/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/clippy_lints/src/attrs/duplicated_attributes.rs @@ -31,6 +31,9 @@ fn check_duplicated_attr( attr_paths: &mut FxHashMap<String, Span>, parent: &mut Vec<String>, ) { + if attr.span.from_expansion() { + return; + } let Some(ident) = attr.ident() else { return }; let name = ident.name; if name == sym::doc || name == sym::cfg_attr { @@ -38,6 +41,14 @@ fn check_duplicated_attr( // conditions are the same. return; } + if let Some(direct_parent) = parent.last() + && ["cfg", "cfg_attr"].contains(&direct_parent.as_str()) + && [sym::all, sym::not, sym::any].contains(&name) + { + // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one + // level `cfg`, we leave. + return; + } if let Some(value) = attr.value_str() { emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":"))); } else if let Some(sub_attrs) = attr.meta_item_list() { diff --git a/clippy_lints/src/attrs/inline_always.rs b/clippy_lints/src/attrs/inline_always.rs index cfcd2cc6a00..3b5b80ffefa 100644 --- a/clippy_lints/src/attrs/inline_always.rs +++ b/clippy_lints/src/attrs/inline_always.rs @@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att cx, INLINE_ALWAYS, attr.span, - &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), + format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), ); } } diff --git a/clippy_lints/src/attrs/maybe_misused_cfg.rs b/clippy_lints/src/attrs/maybe_misused_cfg.rs index 5a70866eda5..e6b2e835be8 100644 --- a/clippy_lints/src/attrs/maybe_misused_cfg.rs +++ b/clippy_lints/src/attrs/maybe_misused_cfg.rs @@ -40,7 +40,7 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { cx, MAYBE_MISUSED_CFG, meta.span, - &format!("'test' may be misspelled as '{}'", ident.name.as_str()), + format!("'test' may be misspelled as '{}'", ident.name.as_str()), "did you mean", "test".to_string(), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/attrs/mixed_attributes_style.rs b/clippy_lints/src/attrs/mixed_attributes_style.rs index c2e21cfd330..75a3d7a9ac3 100644 --- a/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -1,30 +1,85 @@ use super::MIXED_ATTRIBUTES_STYLE; use clippy_utils::diagnostics::span_lint; -use rustc_ast::AttrStyle; -use rustc_lint::EarlyContext; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_data_structures::fx::FxHashSet; +use rustc_lint::{LateContext, LintContext}; +use rustc_span::source_map::SourceMap; +use rustc_span::{SourceFile, Span, Symbol}; +use std::sync::Arc; -pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - let mut has_outer = false; - let mut has_inner = false; +#[derive(Hash, PartialEq, Eq)] +enum SimpleAttrKind { + Doc, + /// A normal attribute, with its name symbols. + Normal(Vec<Symbol>), +} + +impl From<&AttrKind> for SimpleAttrKind { + fn from(value: &AttrKind) -> Self { + match value { + AttrKind::Normal(attr) => { + let path_symbols = attr + .item + .path + .segments + .iter() + .map(|seg| seg.ident.name) + .collect::<Vec<_>>(); + Self::Normal(path_symbols) + }, + AttrKind::DocComment(..) => Self::Doc, + } + } +} + +pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { + let mut inner_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default(); + let mut outer_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default(); + + let source_map = cx.sess().source_map(); + let item_src = source_map.lookup_source_file(item_span.lo()); - for attr in &item.attrs { - if attr.span.from_expansion() { + for attr in attrs { + if attr.span.from_expansion() || !attr_in_same_src_as_item(source_map, &item_src, attr.span) { continue; } + + let kind: SimpleAttrKind = (&attr.kind).into(); match attr.style { - AttrStyle::Inner => has_inner = true, - AttrStyle::Outer => has_outer = true, - } + AttrStyle::Inner => { + if outer_attr_kind.contains(&kind) { + lint_mixed_attrs(cx, attrs); + return; + } + inner_attr_kind.insert(kind); + }, + AttrStyle::Outer => { + if inner_attr_kind.contains(&kind) { + lint_mixed_attrs(cx, attrs); + return; + } + outer_attr_kind.insert(kind); + }, + }; } - if !has_outer || !has_inner { +} + +fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) { + let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); + let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { + first.span.with_hi(last.span.hi()) + } else { return; - } - let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion()); - let span = attrs_iter.next().unwrap().span; + }; span_lint( cx, MIXED_ATTRIBUTES_STYLE, - span.with_hi(attrs_iter.last().unwrap().span.hi()), + span, "item has both inner and outer attributes", ); } + +fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Arc<SourceFile>, attr_span: Span) -> bool { + let attr_src = source_map.lookup_source_file(attr_span.lo()); + Arc::ptr_eq(item_src, &attr_src) +} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 675c428948f..684ad7de2f0 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -465,10 +465,20 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks that an item has only one kind of attributes. + /// Checks for items that have the same kind of attributes with mixed styles (inner/outer). /// /// ### Why is this bad? - /// Having both kinds of attributes makes it more complicated to read code. + /// Having both style of said attributes makes it more complicated to read code. + /// + /// ### Known problems + /// This lint currently has false-negatives when mixing same attributes + /// but they have different path symbols, for example: + /// ```ignore + /// #[custom_attribute] + /// pub fn foo() { + /// #![my_crate::custom_attribute] + /// } + /// ``` /// /// ### Example /// ```no_run @@ -486,7 +496,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MIXED_ATTRIBUTES_STYLE, - suspicious, + style, "item has both inner and outer attributes" } @@ -523,6 +533,7 @@ declare_lint_pass!(Attributes => [ USELESS_ATTRIBUTE, BLANKET_CLIPPY_RESTRICTION_LINTS, SHOULD_PANIC_WITHOUT_EXPECT, + MIXED_ATTRIBUTES_STYLE, ]); impl<'tcx> LateLintPass<'tcx> for Attributes { @@ -566,6 +577,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs), _ => {}, } + mixed_attributes_style::check(cx, item.span, attrs); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { @@ -594,7 +606,6 @@ impl_lint_pass!(EarlyAttributes => [ MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, - MIXED_ATTRIBUTES_STYLE, DUPLICATED_ATTRIBUTES, ]); @@ -605,7 +616,6 @@ impl EarlyLintPass for EarlyAttributes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { empty_line_after::check(cx, item); - mixed_attributes_style::check(cx, item); duplicated_attributes::check(cx, &item.attrs); } diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 05da69636c6..486e7c6ec4f 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -58,7 +58,7 @@ pub(super) fn check( clippy_lints, "no need to put clippy lints behind a `clippy` cfg", None, - &format!( + format!( "write instead: `#{}[{}({})]`", if attr.style == AttrStyle::Inner { "!" } else { "" }, ident.name, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 765cc7c0a54..f25a474d9bb 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -267,7 +267,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa cx, AWAIT_HOLDING_INVALID_TYPE, span, - &format!( + format!( "`{}` may not be held across an `await` point per `clippy.toml`", disallowed.path() ), diff --git a/clippy_lints/src/blocks_in_conditions.rs b/clippy_lints/src/blocks_in_conditions.rs index 2eb0dac9742..171f3031860 100644 --- a/clippy_lints/src/blocks_in_conditions.rs +++ b/clippy_lints/src/blocks_in_conditions.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { else { return; }; - let complex_block_message = &format!( + let complex_block_message = format!( "in {desc}, avoid complex blocks or closures with blocks; \ instead, move the block or closure higher and bind it with a `let`", ); @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { let ex = &body.value; if let ExprKind::Block(block, _) = ex.kind { if !body.value.span.from_expansion() && !block.stmts.is_empty() { - span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message); + span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message.clone()); return ControlFlow::Continue(Descend::No); } } diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 74201e9cc30..58c1a2f2706 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { cx, BOOL_ASSERT_COMPARISON, macro_call.span, - &format!("used `{macro_name}!` with a literal bool"), + format!("used `{macro_name}!` with a literal bool"), |diag| { // assert_eq!(...) // ^^^^^^^^^ diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a474356608f..6edfebb5534 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -392,13 +392,13 @@ fn simple_negate(b: Bool) -> Bool { t @ Term(_) => Not(Box::new(t)), And(mut v) => { for el in &mut v { - *el = simple_negate(::std::mem::replace(el, True)); + *el = simple_negate(std::mem::replace(el, True)); } Or(v) }, Or(mut v) => { for el in &mut v { - *el = simple_negate(::std::mem::replace(el, True)); + *el = simple_negate(std::mem::replace(el, True)); } And(v) }, diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 8683cb86e8a..4062212f408 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; -use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; @@ -9,20 +8,16 @@ use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_middle::ty::IsSuggestable; use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// checks for `Box::new(T::default())`, which is better written as - /// `Box::<T>::default()`. + /// checks for `Box::new(Default::default())`, which can be written as + /// `Box::default()`. /// /// ### Why is this bad? - /// First, it's more complex, involving two calls instead of one. - /// Second, `Box::default()` can be faster - /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). + /// `Box::default()` is equivalent and more concise. /// /// ### Example /// ```no_run @@ -34,7 +29,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.66.0"] pub BOX_DEFAULT, - perf, + style, "Using Box::new(T::default()) instead of Box::default()" } @@ -53,14 +48,14 @@ impl LateLintPass<'_> for BoxDefault { && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) // And the single argument to the call is another function call // This is the `T::default()` of `Box::new(T::default())` - && let ExprKind::Call(arg_path, inner_call_args) = arg.kind + && let ExprKind::Call(arg_path, _) = arg.kind // And we are not in a foreign crate's macro && !in_external_macro(cx.sess(), expr.span) // And the argument expression has the same context as the outer call expression // or that we are inside a `vec!` macro expansion && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) - // And the argument is equivalent to `Default::default()` - && is_default_equivalent(cx, arg) + // And the argument is `Default::default()` or the type is specified + && (is_plain_default(cx, arg_path) || (given_type(cx, expr) && is_default_equivalent(cx, arg))) { span_lint_and_sugg( cx, @@ -68,25 +63,7 @@ impl LateLintPass<'_> for BoxDefault { expr.span, "`Box::new(_)` of default value", "try", - if is_plain_default(cx, arg_path) || given_type(cx, expr) { - "Box::default()".into() - } else if let Some(arg_ty) = - cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None) - { - // Check if we can copy from the source expression in the replacement. - // We need the call to have no argument (see `explicit_default_type`). - if inner_call_args.is_empty() - && let Some(ty) = explicit_default_type(arg_path) - && let Some(s) = snippet_opt(cx, ty.span) - { - format!("Box::<{s}>::default()") - } else { - // Otherwise, use the inferred type's formatting. - with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) - } - } else { - return; - }, + "Box::default()".into(), Applicability::MachineApplicable, ); } @@ -105,20 +82,6 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } } -// Checks whether the call is of the form `A::B::f()`. Returns `A::B` if it is. -// -// In the event we have this kind of construct, it's easy to use `A::B` as a replacement in the -// quickfix. `f` must however have no parameter. Should `f` have some, then some of the type of -// `A::B` may be inferred from the arguments. This would be the case for `Vec::from([0; false])`, -// where the argument to `from` allows inferring this is a `Vec<bool>` -fn explicit_default_type<'a>(arg_path: &'a Expr<'_>) -> Option<&'a Ty<'a>> { - if let ExprKind::Path(QPath::TypeRelative(ty, _)) = &arg_path.kind { - Some(ty) - } else { - None - } -} - fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { macro_backtrace(expr.span).next().map_or(false, |call| { cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) @@ -129,7 +92,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) struct InferVisitor(bool); impl<'tcx> Visitor<'tcx> for InferVisitor { - fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) { + fn visit_ty(&mut self, t: &Ty<'_>) { self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..)); if !self.0 { walk_ty(self, t); diff --git a/clippy_lints/src/cargo/common_metadata.rs b/clippy_lints/src/cargo/common_metadata.rs index 99fe6c1e790..3af2d8c0256 100644 --- a/clippy_lints/src/cargo/common_metadata.rs +++ b/clippy_lints/src/cargo/common_metadata.rs @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { let message = format!("package `{}` is missing `{field}` metadata", package.name); - span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); + span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message); } fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: &Option<T>) -> bool { diff --git a/clippy_lints/src/cargo/feature_name.rs b/clippy_lints/src/cargo/feature_name.rs index 9e69919c727..6982b96dd3b 100644 --- a/clippy_lints/src/cargo/feature_name.rs +++ b/clippy_lints/src/cargo/feature_name.rs @@ -56,13 +56,13 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { REDUNDANT_FEATURE_NAMES }, DUMMY_SP, - &format!( + format!( "the \"{substring}\" {} in the feature name \"{feature}\" is {}", if is_prefix { "prefix" } else { "suffix" }, if is_negative { "negative" } else { "redundant" } ), None, - &format!( + format!( "consider renaming the feature to \"{}\"{}", if is_prefix { feature.strip_prefix(substring) diff --git a/clippy_lints/src/cargo/lint_groups_priority.rs b/clippy_lints/src/cargo/lint_groups_priority.rs index a39b972b56a..a3291c9da10 100644 --- a/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/clippy_lints/src/cargo/lint_groups_priority.rs @@ -102,7 +102,7 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, cx, LINT_GROUPS_PRIORITY, toml_span(group.span(), file), - &format!( + format!( "lint group `{}` has the same priority ({priority}) as a lint", group.as_ref() ), diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 95d5449781b..ca7fa4e5a41 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -241,7 +241,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in NO_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); + span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}")); } }, } @@ -257,7 +257,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in WITH_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); + span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}")); } }, } diff --git a/clippy_lints/src/cargo/multiple_crate_versions.rs b/clippy_lints/src/cargo/multiple_crate_versions.rs index 3f30a77fcfe..2769463c8a5 100644 --- a/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -52,7 +52,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, allowed_duplicate cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, - &format!("multiple versions for dependency `{name}`: {versions}"), + format!("multiple versions for dependency `{name}`: {versions}"), ); } } diff --git a/clippy_lints/src/cargo/wildcard_dependencies.rs b/clippy_lints/src/cargo/wildcard_dependencies.rs index 244e98eb666..0cf687d0192 100644 --- a/clippy_lints/src/cargo/wildcard_dependencies.rs +++ b/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { cx, WILDCARD_DEPENDENCIES, DUMMY_SP, - &format!("wildcard dependency for `{}`", dep.name), + format!("wildcard dependency for `{}`", dep.name), ); } } diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index a667ea04af0..f05fd3fcde5 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, AS_PTR_CAST_MUT, expr.span, - &format!("casting the result of `as_ptr` to *mut {ptrty}"), + format!("casting the result of `as_ptr` to *mut {ptrty}"), "replace with", format!("{recv}.as_mut_ptr()"), applicability, diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index c1663348321..d4d5ee37bcc 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -34,7 +34,7 @@ pub(super) fn check( cx, CAST_ABS_TO_UNSIGNED, span, - &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), + format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()), Applicability::MachineApplicable, diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 86f4332d05a..d52ad1c6f23 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -68,7 +68,7 @@ pub(super) fn check( cx, CAST_LOSSLESS, expr.span, - &message, + message, "try", format!("{cast_to_fmt}::from({sugg})"), app, diff --git a/clippy_lints/src/casts/cast_nan_to_int.rs b/clippy_lints/src/casts/cast_nan_to_int.rs index da756129db3..1743ce71add 100644 --- a/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/clippy_lints/src/casts/cast_nan_to_int.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, CAST_NAN_TO_INT, expr.span, - &format!("casting a known NaN to {to_ty}"), + format!("casting a known NaN to {to_ty}"), None, "this always evaluates to 0", ); diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 2c0a3d48296..dbfa8e1ee91 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -41,7 +41,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b }) }, BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) - .unwrap_or(u64::max_value()) + .unwrap_or(u64::MAX) .min(apply_reductions(cx, nbits, left, signed)), BinOpKind::Shr => apply_reductions(cx, nbits, left, signed) .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())), @@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } else { None }; - apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) + apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) }, ExprKind::MethodCall(method, _, [lo, hi], _) => { if method.ident.as_str() == "clamp" { @@ -142,7 +142,7 @@ pub(super) fn check( cx, CAST_ENUM_TRUNCATION, expr.span, - &format!( + format!( "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}", variant.name, ), @@ -163,7 +163,7 @@ pub(super) fn check( _ => return, }; - span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { + span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, msg, |diag| { diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ..."); if !cast_from.is_floating_point() { offer_suggestion(cx, expr, cast_expr, cast_to_span, diag); diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 2ddb0f00ecd..11274383595 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca ), }; - span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, &message, |diag| { + span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, message, |diag| { if let EmitState::LintOnPtrSize(16) = should_lint { diag .note("`usize` and `isize` may be as small as 16 bits on some platforms") diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 334e1646cd4..035666e4d4c 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -38,7 +38,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca cx, CAST_PRECISION_LOSS, expr.span, - &format!( + format!( "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \ but `{1}`'s mantissa is only {4} bits wide)", cast_from, diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 4d1a0f678f4..960c81045e3 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -48,7 +48,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f cx, CAST_PTR_ALIGNMENT, expr.span, - &format!( + format!( "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)", from_layout.align.abi.bytes(), to_layout.align.abi.bytes(), diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 8fd95d9654c..2b6e17dc103 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -47,7 +47,7 @@ pub(super) fn check<'cx>( cx, CAST_SIGN_LOSS, expr.span, - &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), + format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), ); } } @@ -118,7 +118,7 @@ enum Sign { Uncertain, } -fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign { +fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into<Option<Ty<'cx>>>) -> Sign { // Try evaluate this expr first to see if it's positive if let Some(val) = get_const_signed_int_eval(cx, expr, ty) { return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative }; @@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T // Peel unwrap(), expect(), etc. while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name) && let Some(arglist) = method_chain_args(expr, &[found_name]) - && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind + && let ExprKind::MethodCall(inner_path, recv, ..) = &arglist[0].0.kind { // The original type has changed, but we can't use `ty` here anyway, because it has been // moved. method_name = inner_path.ident.name.as_str(); + expr = recv; } if METHODS_POW.iter().any(|&name| method_name == name) diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs index 76d5c329179..285f0357112 100644 --- a/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv cx, CAST_SLICE_DIFFERENT_SIZES, expr.span, - &format!( + format!( "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count", start_ty.ty, end_ty.ty, ), diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 48629b6c5cc..1d89f6c75e1 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, CAST_SLICE_FROM_RAW_PARTS, span, - &format!("casting the result of `{func}` to {cast_to}"), + format!("casting the result of `{func}` to {cast_to}"), "replace with", format!("core::ptr::slice_{func}({ptr}, {len})"), applicability, diff --git a/clippy_lints/src/casts/fn_to_numeric_cast.rs b/clippy_lints/src/casts/fn_to_numeric_cast.rs index a26bfab4e7c..f263bec1576 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST, expr.span, - &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), + format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "try", format!("{from_snippet} as usize"), applicability, diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index 75654129408..826589bf303 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_ANY, expr.span, - &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), + format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "did you mean to invoke the function?", format!("{from_snippet}() as {cast_to}"), applicability, diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 556be1d1506..0e11bcfb8ec 100644 --- a/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, expr.span, - &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), + format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), "try", format!("{from_snippet} as usize"), applicability, diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 5a121e6a7eb..68841076f77 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -62,8 +62,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { // we omit following `cast`: let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind + && let Some(method_defid) = path.res.opt_def_id() { - let method_defid = path.res.def_id(); if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) { OmitFollowedCastReason::Null(qpath) } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) { diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index e88146331ca..921693567fc 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( PTR_CAST_CONSTNESS, expr.span, "`as` casting between raw pointers while changing only its constness", - &format!("try `pointer::cast_{constness}`, a safer alternative"), + format!("try `pointer::cast_{constness}`, a safer alternative"), format!("{}.cast_{constness}()", sugg.maybe_par()), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 148d52cb5dd..a7f7bf7854e 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_CAST, expr.span, - &format!( + format!( "casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)" ), "try", @@ -166,7 +166,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_CAST, expr.span, - &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), + format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", if needs_block { format!("{{ {cast_str} }}") @@ -209,7 +209,7 @@ fn lint_unnecessary_cast( cx, UNNECESSARY_CAST, expr.span, - &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), + format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), "try", sugg, Applicability::MachineApplicable, diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 7dac3c5d9da..ee1bb63b50d 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -121,7 +121,7 @@ impl CognitiveComplexity { cx, COGNITIVE_COMPLEXITY, fn_span, - &format!( + format!( "the function has a cognitive complexity of ({cc}/{})", self.limit.limit() ), diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index e921b9b46a6..6942ca53640 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } -fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool { let ty = cx.typeck_results().pat_ty(local.pat); collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) // String type is a lang item but not a diagnostic item for now so we need a separate check diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index c8e148598a2..5ff7d8e5134 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -254,6 +254,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::large_include_file::LARGE_INCLUDE_FILE_INFO, crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::large_stack_frames::LARGE_STACK_FRAMES_INFO, + crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::LEN_ZERO_INFO, @@ -678,6 +679,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO, crate::transmute::CROSSPOINTER_TRANSMUTE_INFO, crate::transmute::EAGER_TRANSMUTE_INFO, + crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO, crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO, crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO, crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 98a6d9370c3..2b3f4854255 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { cx, DEFAULT_TRAIT_ACCESS, expr.span, - &format!("calling `{replacement}` is more clear than this expression"), + format!("calling `{replacement}` is more clear than this expression"), "try", replacement, Applicability::Unspecified, // First resolve the TODO above @@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { first_assign.unwrap().span, "field assignment outside of initializer for an instance created with Default::default()", Some(local.span), - &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"), + format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"), ); self.reassigned_linted.insert(span); } diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 71e1a25c2bc..13778175496 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -56,7 +56,7 @@ fn is_alias(ty: hir::Ty<'_>) -> bool { impl LateLintPass<'_> for DefaultConstructedUnitStructs { fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind + if let ExprKind::Call(fn_expr, &[]) = expr.kind // make sure we have a call to `Default::default` && let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind // make sure this isn't a type alias: diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index e617c19eff0..ac49e6f1a48 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, expr.span, - &format!("`{path}()` is the more idiomatic way"), + format!("`{path}()` is the more idiomatic way"), "try", sugg, applicability, @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { fn make_sugg( cx: &LateContext<'_>, - ty_path: &rustc_hir::QPath<'_>, + ty_path: &QPath<'_>, ctxt: SyntaxContext, applicability: &mut Applicability, path: &str, diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index bfd89bfd2c7..3f87ed8df2b 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { item.span, "this union has the default representation", None, - &format!( + format!( "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout", cx.tcx.def_path_str(item.owner_id) ), diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index b0f46f5c646..80327586fed 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -79,7 +79,7 @@ fn is_path_self(e: &Expr<'_>) -> bool { fn contains_trait_object(ty: Ty<'_>) -> bool { match ty.kind() { ty::Ref(_, ty, _) => contains_trait_object(*ty), - ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object), + Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object), ty::Dynamic(..) => true, _ => false, } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index c554edc8fce..5f9700b76d9 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -11,8 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, - TyCtxt, + self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 4a617ba34d5..871f529da6c 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -102,11 +102,11 @@ impl DisallowedMacros { DISALLOWED_MACROS, cx.tcx.local_def_id_to_hir_id(derive_src.def_id), mac.span, - &msg, + msg, add_note, ); } else { - span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, &msg, add_note); + span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, msg, add_note); } } } diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 1868d3cd391..9de879604e2 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { None => return, }; let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| { + span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| { if let Some(reason) = conf.reason() { diag.note(reason); } diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 09dad5554ad..2afbf184117 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedNames { cx, DISALLOWED_NAMES, ident.span, - &format!("use of a disallowed/placeholder name `{}`", ident.name), + format!("use of a disallowed/placeholder name `{}`", ident.name), ); } } diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 0c1bb2da7e8..def4b5932b4 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -98,7 +98,7 @@ impl EarlyLintPass for DisallowedScriptIdents { cx, DISALLOWED_SCRIPT_IDENTS, span, - &format!( + format!( "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", script.full_name() ), diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 130f56b698f..4196309a22a 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -127,7 +127,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) { cx, DISALLOWED_TYPES, span, - &format!("`{name}` is not allowed according to config"), + format!("`{name}` is not allowed according to config"), |diag| { if let Some(reason) = conf.reason() { diag.note(reason); diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index bf6f54c1e72..119473c2454 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -129,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { cx, lint, expr.span, - &msg, + msg, note_span, - &format!("argument has type `{arg_ty}`"), + format!("argument has type `{arg_ty}`"), ); } } diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs index 471335c098f..ed27e38ef2d 100644 --- a/clippy_lints/src/duplicate_mod.rs +++ b/clippy_lints/src/duplicate_mod.rs @@ -119,7 +119,7 @@ impl EarlyLintPass for DuplicateMod { cx, DUPLICATE_MOD, multi_span, - &format!("file is loaded as a module multiple times: `{}`", local_path.display()), + format!("file is loaded as a module multiple times: `{}`", local_path.display()), None, "replace all but one `mod` item with `use` items", ); diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index b8a817e21b1..dd03df797de 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -197,7 +197,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix cx, lint.as_lint(), expr.span, - &format!( + format!( "usage of the {}`{ty}::{}`{}", if prefix == Prefix::From { "function " } else { "" }, lint.as_name(prefix), diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index dafbf6c8846..b7c9d3d0385 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { cx, MAP_ENTRY, expr.span, - &format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()), + format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()), "try", sugg, app, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index ad589dad350..386d4c3c317 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -177,7 +177,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index eccfc31fdd3..850a4f0eec8 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -3,14 +3,14 @@ use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; use clippy_utils::ty::type_diagnostic_name; use clippy_utils::usage::{local_used_after_expr, local_used_in}; -use clippy_utils::{get_path_from_caller_to_method_type, higher, is_adjusted, path_to_local, path_to_local_id}; +use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, - Ty, TypeVisitableExt, TypeckResults, + self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, + TypeVisitableExt, TypeckResults, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if body.value.span.from_expansion() { if body.params.is_empty() { - if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) { + if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) { // replace `|| vec![]` with `Vec::new` span_lint_and_sugg( cx, diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index c5f7212c4c0..62d5ce24d40 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -120,7 +120,7 @@ impl ExcessiveBools { cx, FN_PARAMS_EXCESSIVE_BOOLS, span, - &format!("more than {} bools in function parameters", self.max_fn_params_bools), + format!("more than {} bools in function parameters", self.max_fn_params_bools), None, "consider refactoring bools into two-variant enums", ); @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { cx, STRUCT_EXCESSIVE_BOOLS, item.span, - &format!("more than {} bools in a struct", self.max_struct_bools), + format!("more than {} bools in a struct", self.max_struct_bools), None, "consider using a state machine or refactoring bools into two-variant enums", ); diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index 3a621d967f4..9ffda645742 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` + /// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]` /// /// ### Why is this bad? /// Exhaustive structs are typically fine, but a project which does diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 2e9bec6a7b0..33bd5a5a9d3 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { cx, EXPLICIT_WRITE, expr.span, - &format!("use of `{used}.unwrap()`"), + format!("use of `{used}.unwrap()`"), "try", format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 538d29eb43d..7484f772e08 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -110,11 +110,11 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi())) } - fn emit_help(&self, spans: Vec<Span>, msg: &str, help: &'static str) { + fn emit_help(&self, spans: Vec<Span>, msg: String, help: &'static str) { span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help); } - fn emit_sugg(&self, spans: Vec<Span>, msg: &str, help: &'static str) { + fn emit_sugg(&self, spans: Vec<Span>, msg: String, help: &'static str) { let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect(); span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| { diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable); @@ -167,7 +167,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .iter() .map(|(_, param)| self.get_bound_span(param)) .collect::<Vec<_>>(); - self.emit_help(spans, &msg, help); + self.emit_help(spans, msg, help); } else { let spans = if explicit_params.len() == extra_params.len() { vec![self.generics.span] // Remove the entire list of generics @@ -196,7 +196,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { }) .collect() }; - self.emit_sugg(spans, &msg, help); + self.emit_sugg(spans, msg, help); }; } } diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 981a76d683d..2cd4e9e99a5 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { LitFloatType::Unsuffixed => None, }; let (is_whole, is_inf, mut float_str) = match fty { - FloatTy::F16 => { + FloatTy::F16 | FloatTy::F128 => { // FIXME(f16_f128): do a check like the others when parsing is available return; }, @@ -97,10 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, - FloatTy::F128 => { - // FIXME(f16_f128): do a check like the others when parsing is available - return; - }, }; if is_inf { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index c8b87e510ed..46d47e217b0 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -552,9 +552,9 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) - /// Returns true iff expr is some zero literal fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match constant_simple(cx, cx.typeck_results(), expr) { - Some(Constant::Int(i)) => i == 0, - Some(Constant::F32(f)) => f == 0.0, - Some(Constant::F64(f)) => f == 0.0, + Some(Int(i)) => i == 0, + Some(F32(f)) => f == 0.0, + Some(F64(f)) => f == 0.0, _ => false, } } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 61f550ce0be..80db617c639 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { self.cx, FORMAT_IN_FORMAT_ARGS, self.macro_call.span, - &format!("`format!` in `{name}!` args"), + format!("`format!` in `{name}!` args"), |diag| { diag.help(format!( "combine the `format!(..)` arguments with the outer `{name}!(..)` call" @@ -431,7 +431,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { cx, TO_STRING_IN_FORMAT_ARGS, to_string_span.with_lo(receiver.span.hi()), - &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), + format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "remove this", String::new(), Applicability::MachineApplicable, @@ -441,7 +441,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { cx, TO_STRING_IN_FORMAT_ARGS, value.span, - &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), + format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "use this", format!( "{}{:*>n_needed_derefs$}{receiver_snippet}", diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 93517076cda..0a52347940a 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { self.cx, RECURSIVE_FORMAT_IMPL, self.expr.span, - &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), + format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), ); } } @@ -235,7 +235,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { self.cx, PRINT_IN_FORMAT_IMPL, macro_call.span, - &format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name), + format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name), "replace with", if let Some(formatter_name) = self.format_trait_impl.formatter_name { format!("{replacement}!({formatter_name}, ..)") diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index c3ef6f180c9..34e93bdb9b9 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -151,12 +151,12 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_ASSIGNMENT_FORMATTING, eqop_span, - &format!( + format!( "this looks like you are trying to use `.. {op}= ..`, but you \ really are doing `.. = ({op} ..)`" ), None, - &format!("to remove this lint, use either `{op}=` or `= {op}`"), + format!("to remove this lint, use either `{op}=` or `= {op}`"), ); } } @@ -187,12 +187,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_UNARY_OP_FORMATTING, eqop_span, - &format!( + format!( "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ `{binop_str}{unop_str}` is a single operator" ), None, - &format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"), + format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"), ); } } @@ -215,6 +215,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { // it’s bad when there is a ‘\n’ after the “else” && let Some(else_snippet) = snippet_opt(cx, else_span) && let Some((pre_else, post_else)) = else_snippet.split_once("else") + && !else_snippet.contains('/') && let Some((_, post_else_post_eol)) = post_else.split_once('\n') { // Allow allman style braces `} \n else \n {` @@ -238,9 +239,9 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this is an `else {else_desc}` but the formatting might hide it"), + format!("this is an `else {else_desc}` but the formatting might hide it"), None, - &format!( + format!( "to remove this lint, remove the `else` or remove the new line between \ `else` and `{else_desc}`", ), @@ -308,9 +309,9 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this looks like {looks_like} but the `else` is missing"), + format!("this looks like {looks_like} but the `else` is missing"), None, - &format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",), + format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",), ); } } diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 286ba2306c9..ba2495c17a2 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{RawPtr}; +use rustc_middle::ty::RawPtr; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -52,7 +52,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { cx, FROM_RAW_WITH_VOID_PTR, expr.span, - &msg, + msg, Some(arg.span), "cast this to a pointer of the appropriate type", ); diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index d752d010f9f..d0c66900c00 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -142,7 +142,7 @@ fn check_must_use_candidate<'tcx>( item_span: Span, item_id: hir::OwnerId, fn_span: Span, - msg: &str, + msg: &'static str, ) { if has_mutable_arg(cx, body) || mutates_static(cx, body) @@ -207,9 +207,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) }, ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)), ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys), - ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => { - mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys) - }, + ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys), // calling something constitutes a side effect, so return true on all callables // also never calls need not be used, so return true for them, too _ => true, diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 37fbf2c7d59..93f088d3e33 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -2,7 +2,7 @@ use rustc_errors::Diag; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Adt, Ty}; +use rustc_middle::ty::{Adt, Ty}; use rustc_span::{sym, Span}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; @@ -25,7 +25,7 @@ fn result_err_ty<'tcx>( .tcx .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output()) && is_type_diagnostic_item(cx, ty, sym::Result) - && let ty::Adt(_, args) = ty.kind() + && let Adt(_, args) = ty.kind() { let err_ty = args.type_at(1); Some((hir_ty, err_ty)) diff --git a/clippy_lints/src/functions/too_many_arguments.rs b/clippy_lints/src/functions/too_many_arguments.rs index 1e08922a616..e72a2ad49d8 100644 --- a/clippy_lints/src/functions/too_many_arguments.rs +++ b/clippy_lints/src/functions/too_many_arguments.rs @@ -59,7 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span, cx, TOO_MANY_ARGUMENTS, fn_span, - &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"), + format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"), ); } } diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 34f1bf3b2b1..586ca58d60d 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -77,7 +77,7 @@ pub(super) fn check_fn( cx, TOO_MANY_LINES, span, - &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), + format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), ); } } diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 8f48941c4a9..f5ba62ae432 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -117,9 +117,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { cx, IF_THEN_SOME_ELSE_NONE, expr.span, - &format!("this could be simplified with `bool::{method_name}`"), + format!("this could be simplified with `bool::{method_name}`"), None, - &help, + help, ); } } diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 8acb138332c..a46aae36d5c 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { cx, IMPLICIT_HASHER, target.span(), - &format!( + format!( "impl for `{}` should be generalized over different hashers", target.type_name() ), @@ -187,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { cx, IMPLICIT_HASHER, target.span(), - &format!( + format!( "parameter of type `{}` should be generalized over different hashers", target.type_name() ), diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 9f4d7b51271..7b97fc15caa 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -56,7 +56,7 @@ fn emit_lint( index: usize, // The bindings that were implied, used for suggestion purposes since removing a bound with associated types // means we might need to then move it to a different bound - implied_bindings: &[rustc_hir::TypeBinding<'_>], + implied_bindings: &[TypeBinding<'_>], bound: &ImplTraitBound<'_>, ) { let implied_by = snippet(cx, bound.span, ".."); @@ -65,7 +65,7 @@ fn emit_lint( cx, IMPLIED_BOUNDS_IN_IMPLS, poly_trait.span, - &format!("this bound is already specified as the supertrait of `{implied_by}`"), + format!("this bound is already specified as the supertrait of `{implied_by}`"), |diag| { // If we suggest removing a bound, we may also need to extend the span // to include the `+` token that is ahead or behind, diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index cd000fcd184..35b4481bfee 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// To fix this problem, either increase your MSRV or use another item /// available in your current MSRV. - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub INCOMPATIBLE_MSRV, suspicious, "ensures that all items used in the crate are available for the current MSRV" @@ -104,7 +104,7 @@ impl IncompatibleMsrv { cx, INCOMPATIBLE_MSRV, span, - &format!( + format!( "current MSRV (Minimum Supported Rust Version) is `{}` but this item is stable since `{version}`", self.msrv ), diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index ca2ac60306b..157f6105984 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -132,20 +132,20 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { cx, INHERENT_TO_STRING_SHADOW_DISPLAY, item.span, - &format!( + format!( "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`" ), None, - &format!("remove the inherent method from type `{self_type}`"), + format!("remove the inherent method from type `{self_type}`"), ); } else { span_lint_and_help( cx, INHERENT_TO_STRING, item.span, - &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"), + format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"), None, - &format!("implement trait `Display` for type `{self_type}` instead"), + format!("implement trait `Display` for type `{self_type}` instead"), ); } } diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 83ecaeef982..860258fd030 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { cx, INLINE_FN_WITHOUT_BODY, attr.span, - &format!("use of `#[inline]` on trait method `{name}` which has no body"), + format!("use of `#[inline]` on trait method `{name}` which has no body"), |diag| { diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); }, diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 17b6256f982..10b00f632bb 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::{self, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty; @@ -149,7 +149,7 @@ fn print_unchecked_duration_subtraction_sugg( let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "<instant>", &mut applicability).0; let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "<duration>", &mut applicability).0; - diagnostics::span_lint_and_sugg( + span_lint_and_sugg( cx, UNCHECKED_DURATION_SUBTRACTION, expr.span, diff --git a/clippy_lints/src/integer_division_remainder_used.rs b/clippy_lints/src/integer_division_remainder_used.rs index 36dc45ca788..a3577b765c0 100644 --- a/clippy_lints/src/integer_division_remainder_used.rs +++ b/clippy_lints/src/integer_division_remainder_used.rs @@ -43,7 +43,7 @@ impl LateLintPass<'_> for IntegerDivisionRemainderUsed { cx, INTEGER_DIVISION_REMAINDER_USED, expr.span.source_callsite(), - &format!("use of {} has been disallowed in this context", op.node.as_str()), + format!("use of {} has been disallowed in this context", op.node.as_str()), ); } } diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index 8bcd9b532bd..30f2285bdd2 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -76,7 +76,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa cx, INVALID_UPCAST_COMPARISONS, span, - &format!( + format!( "because of the numeric bounds on `{}` prior to casting, this expression is always {}", snippet(cx, cast_val.span, "the expression"), if always { "true" } else { "false" }, @@ -88,7 +88,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa fn upcast_comparison_bounds_err<'tcx>( cx: &LateContext<'tcx>, span: Span, - rel: comparisons::Rel, + rel: Rel, lhs_bounds: Option<(FullInt, FullInt)>, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 0b4c416d94d..6615122567d 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -240,9 +240,9 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: & cx, STRUCT_FIELD_NAMES, item.span, - &format!("all fields have the same {what}fix: `{value}`"), + format!("all fields have the same {what}fix: `{value}`"), None, - &format!("remove the {what}fixes"), + format!("remove the {what}fixes"), ); } } @@ -370,9 +370,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n cx, ENUM_VARIANT_NAMES, span, - &format!("all variants have the same {what}fix: `{value}`"), + format!("all variants have the same {what}fix: `{value}`"), None, - &format!( + format!( "remove the {what}fixes and use full paths to \ the variants instead of glob imports" ), diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index 32ae6be5687..1b5f1b49947 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -84,7 +84,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI cx, ITER_NOT_RETURNING_ITERATOR, sig.span, - &format!("this method is named `{name}` but its return type does not implement `Iterator`"), + format!("this method is named `{name}` but its return type does not implement `Iterator`"), ); } } diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index cf0ab88032c..c749a712330 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -182,7 +182,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { cx, INTO_ITER_WITHOUT_ITER, item.span, - &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), + format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), |diag| { // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS // to avoid name ambiguities, as there might be an inherent into_iter method @@ -258,7 +258,7 @@ impl {self_ty_without_ref} {{ cx, ITER_WITHOUT_INTO_ITER, item.span, - &format!( + format!( "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident ), diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index eb7570e9b44..07488a512a3 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { cx, LARGE_FUTURES, expr.span, - &format!("large future with a size of {} bytes", size.bytes()), + format!("large future with a size of {} bytes", size.bytes()), "consider `Box::pin` on it", format!("Box::pin({})", snippet(cx, expr.span, "..")), Applicability::Unspecified, diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 1b5981ecc28..0599afca09f 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -74,7 +74,7 @@ impl LateLintPass<'_> for LargeIncludeFile { expr.span, "attempted to include a large file", None, - &format!( + format!( "the configuration allows a maximum size of {} bytes", self.max_file_size ), diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index fd33ba91bfd..afcb6745947 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { cx, LARGE_STACK_ARRAYS, expr.span, - &format!( + format!( "allocating a local array larger than {} bytes", self.maximum_allowed_size ), None, - &format!( + format!( "consider allocating on the heap with `vec!{}.into_boxed_slice()`", snippet(cx, expr.span, "[...]") ), diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index b397180a69c..49408d7e243 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -1,10 +1,12 @@ -use std::ops::AddAssign; +use std::{fmt, ops}; -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_has_unsatisfiable_preds; +use clippy_utils::source::snippet_opt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; +use rustc_lexer::is_ident; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -108,13 +110,25 @@ impl Space { } } -impl AddAssign<u64> for Space { - fn add_assign(&mut self, rhs: u64) { - if let Self::Used(lhs) = self { - match lhs.checked_add(rhs) { - Some(sum) => *self = Self::Used(sum), - None => *self = Self::Overflow, - } +impl fmt::Display for Space { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Space::Used(1) => write!(f, "1 byte"), + Space::Used(n) => write!(f, "{n} bytes"), + Space::Overflow => write!(f, "over 2⁶⁴-1 bytes"), + } + } +} + +impl ops::Add<u64> for Space { + type Output = Self; + fn add(self, rhs: u64) -> Self { + match self { + Self::Used(lhs) => match lhs.checked_add(rhs) { + Some(sum) => Self::Used(sum), + None => Self::Overflow, + }, + Self::Overflow => self, } } } @@ -123,10 +137,10 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, + fn_kind: FnKind<'tcx>, _: &'tcx FnDecl<'tcx>, _: &'tcx Body<'tcx>, - span: Span, + entire_fn_span: Span, local_def_id: LocalDefId, ) { let def_id = local_def_id.to_def_id(); @@ -138,22 +152,68 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { let mir = cx.tcx.optimized_mir(def_id); let param_env = cx.tcx.param_env(def_id); - let mut frame_size = Space::Used(0); + let sizes_of_locals = || { + mir.local_decls.iter().filter_map(|local| { + let layout = cx.tcx.layout_of(param_env.and(local.ty)).ok()?; + Some((local, layout.size.bytes())) + }) + }; - for local in &mir.local_decls { - if let Ok(layout) = cx.tcx.layout_of(param_env.and(local.ty)) { - frame_size += layout.size.bytes(); - } - } + let frame_size = sizes_of_locals().fold(Space::Used(0), |sum, (_, size)| sum + size); + + let limit = self.maximum_allowed_size; + if frame_size.exceeds_limit(limit) { + // Point at just the function name if possible, because lints that span + // the entire body and don't have to are less legible. + let fn_span = match fn_kind { + FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, + FnKind::Closure => entire_fn_span, + }; - if frame_size.exceeds_limit(self.maximum_allowed_size) { - span_lint_and_note( + span_lint_and_then( cx, LARGE_STACK_FRAMES, - span, - "this function allocates a large amount of stack space", - None, - "allocating large amounts of stack space can overflow the stack", + fn_span, + format!("this function may allocate {frame_size} on the stack"), + |diag| { + // Point out the largest individual contribution to this size, because + // it is the most likely to be unintentionally large. + if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size) { + let local_span: Span = local.source_info.span; + let size = Space::Used(size); // pluralizes for us + let ty = local.ty; + + // TODO: Is there a cleaner, robust way to ask this question? + // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", + // and that doesn't get us the true name in scope rather than the span text either. + if let Some(name) = snippet_opt(cx, local_span) + && is_ident(&name) + { + // If the local is an ordinary named variable, + // print its name rather than relying solely on the span. + diag.span_label( + local_span, + format!("`{name}` is the largest part, at {size} for type `{ty}`"), + ); + } else { + diag.span_label( + local_span, + format!("this is the largest part, at {size} for type `{ty}`"), + ); + } + } + + // Explain why we are linting this and not other functions. + diag.note(format!( + "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}" + )); + + // Explain why the user should care, briefly. + diag.note_once( + "allocating large amounts of stack space can overflow the stack \ + and cause the program to abort", + ); + }, ); } } diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs new file mode 100644 index 00000000000..c5f1afe68c3 --- /dev/null +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -0,0 +1,293 @@ +use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::{get_parent_expr, is_from_proc_macro}; +use hir::def_id::DefId; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_hir as hir; +use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::impl_lint_pass; +use rustc_span::symbol::kw; +use rustc_span::{sym, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `<integer>::max_value()`, `std::<integer>::MAX`, + /// `std::<float>::EPSILON`, etc. + /// + /// ### Why is this bad? + /// All of these have been superceded by the associated constants on their respective types, + /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust. + /// + /// ### Example + /// ```rust + /// let eps = std::f32::EPSILON; + /// ``` + /// Use instead: + /// ```rust + /// let eps = f32::EPSILON; + /// ``` + #[clippy::version = "1.72.0"] + pub LEGACY_NUMERIC_CONSTANTS, + style, + "checks for usage of legacy std numeric constants and methods" +} +pub struct LegacyNumericConstants { + msrv: Msrv, +} + +impl LegacyNumericConstants { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]); + +impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let Self { msrv } = self; + + if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) { + return; + } + + // Integer modules are "TBD" deprecated, and the contents are too, + // so lint on the `use` statement directly. + if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind + && let Some(def_id) = path.res[0].opt_def_id() + { + let module = if is_integer_module(cx, def_id) { + true + } else if is_numeric_const(cx, def_id) { + false + } else { + return; + }; + + span_lint_and_then( + cx, + LEGACY_NUMERIC_CONSTANTS, + path.span, + if module { + "importing legacy numeric constants" + } else { + "importing a legacy numeric constant" + }, + |diag| { + if item.ident.name == kw::Underscore { + diag.help("remove this import"); + return; + } + + let def_path = cx.get_def_path(def_id); + + if module && let [.., module_name] = &*def_path { + if kind == UseKind::Glob { + diag.help(format!("remove this import and use associated constants `{module_name}::<CONST>` from the primitive type instead")); + } else { + diag.help("remove this import").note(format!( + "then `{module_name}::<CONST>` will resolve to the respective associated constant" + )); + } + } else if let [.., module_name, name] = &*def_path { + diag.help( + format!("remove this import and use the associated constant `{module_name}::{name}` from the primitive type instead") + ); + } + }, + ); + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + let Self { msrv } = self; + + if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { + return; + } + let ExprKind::Path(qpath) = expr.kind else { + return; + }; + + // `std::<integer>::<CONST>` check + let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath + && let Some(def_id) = path.res.opt_def_id() + && is_numeric_const(cx, def_id) + && let def_path = cx.get_def_path(def_id) + && let [.., mod_name, name] = &*def_path + // Skip linting if this usage looks identical to the associated constant, + // since this would only require removing a `use` import (which is already linted). + && !is_numeric_const_path_canonical(path, [*mod_name, *name]) + { + ( + expr.span, + format!("{mod_name}::{name}"), + "usage of a legacy numeric constant", + ) + // `<integer>::xxx_value` check + } else if let QPath::TypeRelative(_, last_segment) = qpath + && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() + && is_integer_method(cx, def_id) + && let Some(par_expr) = get_parent_expr(cx, expr) + && let ExprKind::Call(_, _) = par_expr.kind + { + let name = last_segment.ident.name.as_str(); + + ( + last_segment.ident.span.with_hi(par_expr.span.hi()), + name[..=2].to_ascii_uppercase(), + "usage of a legacy numeric method", + ) + } else { + return; + }; + + if is_from_proc_macro(cx, expr) { + return; + } + + span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { + diag.span_suggestion_with_style( + span, + "use the associated constant instead", + sugg, + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + }); + } + + extract_msrv_attr!(LateContext); +} + +fn is_integer_module(cx: &LateContext<'_>, did: DefId) -> bool { + matches!( + cx.tcx.get_diagnostic_name(did), + Some( + sym::isize_legacy_mod + | sym::i128_legacy_mod + | sym::i64_legacy_mod + | sym::i32_legacy_mod + | sym::i16_legacy_mod + | sym::i8_legacy_mod + | sym::usize_legacy_mod + | sym::u128_legacy_mod + | sym::u64_legacy_mod + | sym::u32_legacy_mod + | sym::u16_legacy_mod + | sym::u8_legacy_mod + ) + ) +} + +fn is_numeric_const(cx: &LateContext<'_>, did: DefId) -> bool { + matches!( + cx.tcx.get_diagnostic_name(did), + Some( + sym::isize_legacy_const_max + | sym::isize_legacy_const_min + | sym::i128_legacy_const_max + | sym::i128_legacy_const_min + | sym::i16_legacy_const_max + | sym::i16_legacy_const_min + | sym::i32_legacy_const_max + | sym::i32_legacy_const_min + | sym::i64_legacy_const_max + | sym::i64_legacy_const_min + | sym::i8_legacy_const_max + | sym::i8_legacy_const_min + | sym::usize_legacy_const_max + | sym::usize_legacy_const_min + | sym::u128_legacy_const_max + | sym::u128_legacy_const_min + | sym::u16_legacy_const_max + | sym::u16_legacy_const_min + | sym::u32_legacy_const_max + | sym::u32_legacy_const_min + | sym::u64_legacy_const_max + | sym::u64_legacy_const_min + | sym::u8_legacy_const_max + | sym::u8_legacy_const_min + | sym::f32_legacy_const_digits + | sym::f32_legacy_const_epsilon + | sym::f32_legacy_const_infinity + | sym::f32_legacy_const_mantissa_dig + | sym::f32_legacy_const_max + | sym::f32_legacy_const_max_10_exp + | sym::f32_legacy_const_max_exp + | sym::f32_legacy_const_min + | sym::f32_legacy_const_min_10_exp + | sym::f32_legacy_const_min_exp + | sym::f32_legacy_const_min_positive + | sym::f32_legacy_const_nan + | sym::f32_legacy_const_neg_infinity + | sym::f32_legacy_const_radix + | sym::f64_legacy_const_digits + | sym::f64_legacy_const_epsilon + | sym::f64_legacy_const_infinity + | sym::f64_legacy_const_mantissa_dig + | sym::f64_legacy_const_max + | sym::f64_legacy_const_max_10_exp + | sym::f64_legacy_const_max_exp + | sym::f64_legacy_const_min + | sym::f64_legacy_const_min_10_exp + | sym::f64_legacy_const_min_exp + | sym::f64_legacy_const_min_positive + | sym::f64_legacy_const_nan + | sym::f64_legacy_const_neg_infinity + | sym::f64_legacy_const_radix + ) + ) +} + +// Whether path expression looks like `i32::MAX` +fn is_numeric_const_path_canonical(expr_path: &hir::Path<'_>, [mod_name, name]: [Symbol; 2]) -> bool { + let [ + hir::PathSegment { + ident: one, args: None, .. + }, + hir::PathSegment { + ident: two, args: None, .. + }, + ] = expr_path.segments + else { + return false; + }; + + one.name == mod_name && two.name == name +} + +fn is_integer_method(cx: &LateContext<'_>, did: DefId) -> bool { + matches!( + cx.tcx.get_diagnostic_name(did), + Some( + sym::isize_legacy_fn_max_value + | sym::isize_legacy_fn_min_value + | sym::i128_legacy_fn_max_value + | sym::i128_legacy_fn_min_value + | sym::i16_legacy_fn_max_value + | sym::i16_legacy_fn_min_value + | sym::i32_legacy_fn_max_value + | sym::i32_legacy_fn_min_value + | sym::i64_legacy_fn_max_value + | sym::i64_legacy_fn_min_value + | sym::i8_legacy_fn_max_value + | sym::i8_legacy_fn_min_value + | sym::usize_legacy_fn_max_value + | sym::usize_legacy_fn_min_value + | sym::u128_legacy_fn_max_value + | sym::u128_legacy_fn_min_value + | sym::u16_legacy_fn_max_value + | sym::u16_legacy_fn_min_value + | sym::u32_legacy_fn_max_value + | sym::u32_legacy_fn_min_value + | sym::u64_legacy_fn_max_value + | sym::u64_legacy_fn_min_value + | sym::u8_legacy_fn_max_value + | sym::u8_legacy_fn_min_value + ) + ) +} diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index cae9ada5a33..97a245b76d4 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_with_context; -use clippy_utils::sugg::Sugg; +use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::sugg::{has_enclosing_paren, Sugg}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { // expr.span might contains parenthesis, see issue #10529 - let actual_span = left.span.with_hi(right.span.hi()); + let actual_span = span_without_enclosing_paren(cx, expr.span); match cmp { BinOpKind::Eq => { check_cmp(cx, actual_span, left, right, "", 0); // len == 0 @@ -218,6 +218,20 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } } +fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { + let Some(snippet) = snippet_opt(cx, span) else { + return span; + }; + if has_enclosing_paren(snippet) { + let source_map = cx.tcx.sess.source_map(); + let left_paren = source_map.start_point(span); + let right_parent = source_map.end_point(span); + left_paren.between(right_parent) + } else { + span + } +} + fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) { fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool { item.ident.name == name @@ -256,7 +270,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { - i.kind == ty::AssocKind::Fn + i.kind == AssocKind::Fn && i.fn_has_self_parameter && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 }); @@ -266,7 +280,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items cx, LEN_WITHOUT_IS_EMPTY, visited_trait.span, - &format!( + format!( "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method", visited_trait.ident.name ), @@ -484,7 +498,7 @@ fn check_for_is_empty( Some(_) => return, }; - span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, &msg, |db| { + span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| { if let Some(span) = is_empty_span { db.span_note(span, "`is_empty` defined here"); } @@ -495,6 +509,10 @@ fn check_for_is_empty( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { + if method.span.from_expansion() { + return; + } + if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { @@ -542,8 +560,8 @@ fn check_len( cx, LEN_ZERO, span, - &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), - &format!("using `{op}is_empty` is clearer and more explicit"), + format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), + format!("using `{op}is_empty` is clearer and more explicit"), format!( "{op}{}.is_empty()", snippet_with_context(cx, receiver.span, span.ctxt(), "_", &mut applicability).0, @@ -566,7 +584,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex COMPARISON_TO_EMPTY, span, "comparison to empty slice", - &format!("using `{op}is_empty` is clearer and more explicit"), + format!("using `{op}is_empty` is clearer and more explicit"), format!("{op}{lit_str}.is_empty()"), applicability, ); @@ -594,7 +612,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if item.kind == ty::AssocKind::Fn { + if item.kind == AssocKind::Fn { let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let ty = sig.skip_binder(); ty.inputs().len() == 1 diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 57fac351042..b92364a9d14 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -16,11 +16,14 @@ rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] -#![warn(trivial_casts, trivial_numeric_casts)] -// warn on lints, that are included in `rust-lang/rust`s bootstrap -#![warn(rust_2018_idioms, unused_lifetimes)] -// warn on rustc internal lints -#![warn(rustc::internal)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications, + rustc::internal +)] // Disable this rustc lint for now, as it was also done in rustc #![allow(rustc::potential_query_instability)] @@ -186,6 +189,7 @@ mod large_futures; mod large_include_file; mod large_stack_arrays; mod large_stack_frames; +mod legacy_numeric_constants; mod len_zero; mod let_if_seq; mod let_underscore; @@ -1080,6 +1084,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_one_hash_in_raw_strings, }) }); + store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(msrv()))); store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); store.register_early_pass(|| Box::new(visibility::Visibility)); store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() })); diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 2b73663d229..a60a40a2a47 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -216,7 +216,7 @@ fn check_fn_inner<'tcx>( None })) .collect_vec(), - &format!("the following explicit lifetimes could be elided: {lts}"), + format!("the following explicit lifetimes could be elided: {lts}"), |diag| { if sig.header.is_async() { // async functions have usages whose spans point at the lifetime declaration which messes up diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 29957e423b0..3d1c666dfea 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -70,7 +70,7 @@ impl LateLintPass<'_> for LinesFilterMapOk { cx, LINES_FILTER_MAP_OK, fm_span, - &format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), + format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), |diag| { diag.span_note( fm_receiver.span, diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index f33151cf4c5..2348dd18220 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -158,7 +158,7 @@ enum WarningType { } impl WarningType { - fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: rustc_span::Span) { + fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: Span) { match self { Self::MistypedLiteralSuffix => span_lint_and_sugg( cx, @@ -302,11 +302,7 @@ impl LiteralDigitGrouping { } // Returns `false` if the check fails - fn check_for_mistyped_suffix( - cx: &EarlyContext<'_>, - span: rustc_span::Span, - num_lit: &mut NumericLiteral<'_>, - ) -> bool { + fn check_for_mistyped_suffix(cx: &EarlyContext<'_>, span: Span, num_lit: &mut NumericLiteral<'_>) -> bool { if num_lit.suffix.is_some() { return true; } diff --git a/clippy_lints/src/loops/explicit_counter_loop.rs b/clippy_lints/src/loops/explicit_counter_loop.rs index 277062a8490..f0ee64d714e 100644 --- a/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/clippy_lints/src/loops/explicit_counter_loop.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{name}` is used as a loop counter"), + format!("the variable `{name}` is used as a loop counter"), "consider using", format!( "for ({name}, {}) in {}.enumerate()", @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{name}` is used as a loop counter"), + format!("the variable `{name}` is used as a loop counter"), |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 94c951fc10a..6922533fbe9 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx cx, FOR_KV_MAP, arg_span, - &format!("you seem to want to iterate on a map's {kind}s"), + format!("you seem to want to iterate on a map's {kind}s"), |diag| { let map = sugg::Sugg::hir(cx, arg, "map"); multispan_sugg( diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 36de9021f49..dbc094a6d73 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( "...and remove the `if let` statement in the for loop" }; - span_lint_and_then(cx, MANUAL_FLATTEN, span, &msg, |diag| { + span_lint_and_then(cx, MANUAL_FLATTEN, span, msg, |diag| { diag.span_suggestion(arg.span, "try", sugg, applicability); diag.span_help(inner_expr.span, help_msg); }); diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index c4e60e98ad4..94330001e4f 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -109,7 +109,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { } } - fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } impl MutatePairDelegate<'_, '_> { @@ -141,7 +141,7 @@ impl BreakAfterExprVisitor { } } -impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor { +impl<'tcx> Visitor<'tcx> for BreakAfterExprVisitor { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if self.past_candidate { return; diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index cf34c904dfe..de7ec81bc01 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -143,7 +143,7 @@ pub(super) fn check<'tcx>( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is used to index `{indexed}`", ident.name), + format!("the loop variable `{}` is used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, @@ -169,7 +169,7 @@ pub(super) fn check<'tcx>( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), + format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, @@ -357,7 +357,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); for (ty, expr) in iter::zip( self.cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(), - std::iter::once(receiver).chain(args.iter()), + iter::once(receiver).chain(args.iter()), ) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = *ty.kind() { diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 8aae7be4593..313a5bfefbc 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -159,12 +159,9 @@ fn never_loop_expr<'tcx>( | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), - ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all( - cx, - std::iter::once(receiver).chain(es.iter()), - local_labels, - main_loop_id, - ), + ExprKind::MethodCall(_, receiver, es, _) => { + never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id) + }, ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(cx, fields.iter().map(|f| f.expr), local_labels, main_loop_id); if let Some(base) = base { diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 670a78d58c3..1d90d4a58f5 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( vec.span, "it looks like the same item is being pushed into this Vec", None, - &format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), + format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), ); } diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 4773a1454b7..108fdb69775 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( }, [], _, - ) if method.ident.name == rustc_span::sym::iter => (arg, "&"), + ) if method.ident.name == sym::iter => (arg, "&"), ExprKind::MethodCall( method, Expr { @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>( }, [], _, - ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""), + ) if method.ident.name == sym::into_iter => (arg, ""), // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise. ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""), _ => return, @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>( cx, SINGLE_ELEMENT_LOOP, arg.span, - format!("this loops only once with `{pat_snip}` being `{range_expr}`").as_str(), + format!("this loops only once with `{pat_snip}` being `{range_expr}`"), "did you mean to iterate over the range instead?", sugg.to_string(), Applicability::Unspecified, diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index a381b35cf2e..72807b4b284 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -51,7 +51,7 @@ impl LateLintPass<'_> for MainRecursion { cx, MAIN_RECURSION, func.span, - &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), + format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), None, "consider using another function for this recursion", ); diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 4f6a2cf017c..76edbe8b755 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -1,7 +1,7 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call; -use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg}; +use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -63,7 +63,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { _ => (cond, "!"), }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); - let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); + let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" }; + let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip}){semicolon}"); // we show to the user the suggestion without the comments, but when applying the fix, include the // comments in the block span_lint_and_then( diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index aa02e4e7a43..24fc2b4faea 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -139,7 +139,7 @@ fn is_ty_conversion(expr: &Expr<'_>) -> bool { if let ExprKind::Cast(..) = expr.kind { true } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind - && path.ident.name == rustc_span::sym::try_into + && path.ident.name == sym::try_into { // This is only called for `usize` which implements `TryInto`. Therefore, // we don't have to check here if `self` implements the `TryInto` trait. diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 830af77968c..1eadc200bed 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; use clippy_utils::sugg::Sugg; @@ -17,6 +18,7 @@ use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; +use std::cmp::Ordering; use std::ops::Deref; declare_clippy_lint! { @@ -26,6 +28,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// clamp is much shorter, easier to read, and doesn't use any control flow. /// + /// ### Limitations + /// + /// This lint will only trigger if max and min are known at compile time, and max is + /// greater than min. + /// /// ### Known issue(s) /// If the clamped variable is NaN this suggestion will cause the code to propagate NaN /// rather than returning either `max` or `min`. @@ -80,7 +87,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.66.0"] pub MANUAL_CLAMP, - nursery, + complexity, "using a clamp pattern instead of the clamp function" } impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); @@ -103,6 +110,26 @@ struct ClampSuggestion<'tcx> { hir_with_ignore_attr: Option<HirId>, } +impl<'tcx> ClampSuggestion<'tcx> { + /// This function will return true if and only if you can demonstrate at compile time that min + /// is less than max. + fn min_less_than_max(&self, cx: &LateContext<'tcx>) -> bool { + let max_type = cx.typeck_results().expr_ty(self.params.max); + let min_type = cx.typeck_results().expr_ty(self.params.min); + if max_type != min_type { + return false; + } + if let Some(max) = constant(cx, cx.typeck_results(), self.params.max) + && let Some(min) = constant(cx, cx.typeck_results(), self.params.min) + && let Some(ord) = Constant::partial_cmp(cx.tcx, max_type, &min, &max) + { + ord != Ordering::Greater + } else { + false + } + } +} + #[derive(Debug)] struct InputMinMax<'tcx> { input: &'tcx Expr<'tcx>, @@ -123,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { .or_else(|| is_match_pattern(cx, expr)) .or_else(|| is_if_elseif_pattern(cx, expr)); if let Some(suggestion) = suggestion { - emit_suggestion(cx, &suggestion); + maybe_emit_suggestion(cx, &suggestion); } } } @@ -133,13 +160,16 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { return; } for suggestion in is_two_if_pattern(cx, block) { - emit_suggestion(cx, &suggestion); + maybe_emit_suggestion(cx, &suggestion); } } extract_msrv_attr!(LateContext); } -fn emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) { +fn maybe_emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) { + if !suggestion.min_less_than_max(cx) { + return; + } let ClampSuggestion { params: InputMinMax { input, diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index bcd02436002..45af9f07718 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -106,12 +106,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { cx, MANUAL_STRIP, strippings[0], - &format!("stripping a {kind_word} manually"), + format!("stripping a {kind_word} manually"), |diag| { diag.span_note(test_span, format!("the {kind_word} was tested here")); multispan_sugg( diag, - &format!("try using the `strip_{kind_word}` method"), + format!("try using the `strip_{kind_word}` method"), vec![( test_span, format!( diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs index ddaf97c463a..c562ceb5bce 100644 --- a/clippy_lints/src/manual_unwrap_or_default.rs +++ b/clippy_lints/src/manual_unwrap_or_default.rs @@ -1,14 +1,15 @@ +use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_default_equivalent; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment}; declare_clippy_lint! { /// ### What it does @@ -118,22 +119,27 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { // We now get the bodies for both the `Some` and `None` arms. && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = body_some.peel_blocks().kind + && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind && let Res::Local(local_id) = path.res && local_id == binding_id // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_none = body_none.peel_blocks() + && let body_none = peel_blocks(body_none) && is_default_equivalent(cx, body_none) - && let Some(match_expr_snippet) = snippet_opt(cx, match_expr.span) + && let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par) { + let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; span_lint_and_sugg( cx, MANUAL_UNWRAP_OR_DEFAULT, expr.span, "match can be simplified with `.unwrap_or_default()`", "replace it with", - format!("{match_expr_snippet}.unwrap_or_default()"), - Applicability::MachineApplicable, + format!("{receiver}.unwrap_or_default()"), + applicability, ); } true @@ -149,14 +155,19 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { && implements_trait(cx, match_ty, default_trait_id, &[]) && let Some(binding_id) = get_some(cx, let_.pat) // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = if_block.peel_blocks().kind + && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind && let Res::Local(local_id) = path.res && local_id == binding_id // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_else = else_expr.peel_blocks() + && let body_else = peel_blocks(else_expr) && is_default_equivalent(cx, body_else) && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span) { + let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; span_lint_and_sugg( cx, MANUAL_UNWRAP_OR_DEFAULT, @@ -164,14 +175,14 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { "if let can be simplified with `.unwrap_or_default()`", "replace it with", format!("{if_let_expr_snippet}.unwrap_or_default()"), - Applicability::MachineApplicable, + applicability, ); } } impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.from_expansion() { + if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { return; } if !handle_match(cx, expr) { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index c9eab7109eb..9db04b615be 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -221,13 +221,13 @@ fn lint_map_unit_fn( binding = let_binding_name(cx, var_arg) ); - span_lint_and_then(cx, lint, expr.span, &msg, |diag| { + span_lint_and_then(cx, lint, expr.span, msg, |diag| { diag.span_suggestion(stmt.span, "try", suggestion, applicability); }); } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) { let msg = suggestion_msg("closure", map_type); - span_lint_and_then(cx, lint, expr.span, &msg, |diag| { + span_lint_and_then(cx, lint, expr.span, msg, |diag| { if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) { let mut applicability = Applicability::MachineApplicable; let suggestion = format!( diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 62cedc8847b..2a5fc8b6609 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { MATCH_RESULT_OK, expr.span.with_hi(let_expr.span.hi()), "matching on `Some` with `ok()` is redundant", - &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), + format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), sugg, applicability, ); diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 5fef5930fab..6746920edc5 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -97,7 +97,7 @@ fn check_arm<'tcx>( } else { String::new() }; - span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, &msg, |diag| { + span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, msg, |diag| { let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); help_span.push_span_label(binding_span, "replace this binding"); help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 3e79cabd795..9edd6c95404 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{ty_name}::unwrap_or`"), + format!("this pattern reimplements `{ty_name}::unwrap_or`"), "replace with", format!("{suggestion}.unwrap_or({reindented_or_body})",), app, diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 6b484ff2749..f5da8ec6187 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -43,7 +43,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: cx, MATCH_AS_REF, expr.span, - &format!("use `{suggestion}()` instead"), + format!("use `{suggestion}()` instead"), "try", format!( "{}.{suggestion}(){cast}", diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index b062e81cefd..64cb7a06ce9 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -122,7 +122,7 @@ where cx, MATCH_LIKE_MATCHES_MACRO, expr.span, - &format!( + format!( "{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" } ), diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index bd38648bcf1..322e9c3ebe5 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -111,7 +111,7 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad MATCH_STR_CASE_MISMATCH, bad_case_span, "this `match` arm has a differing case than its expression", - &format!("consider changing the case of this arm to respect `{method_str}`"), + format!("consider changing the case of this arm to respect `{method_str}`"), format!("\"{suggestion}\""), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index 8a4c0ab9062..d1f637ec78c 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -43,7 +43,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' cx, MATCH_WILD_ERR_ARM, arm.pat.span, - &format!("`Err({ident_bind_name})` matches all errors"), + format!("`Err({ident_bind_name})` matches all errors"), None, "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", ); diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 580d4a64296..fae2c4e4af9 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -25,14 +25,13 @@ mod try_err; mod wild_in_or_pats; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; +use clippy_utils::source::walk_span_to_context; +use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat}; -use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{Span, SpanData, SyntaxContext}; +use rustc_span::{SpanData, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -1196,28 +1195,3 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar Err(()) => true, } } - -/// Checks if the given span contains a `#[cfg(..)]` attribute -fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - let Some(snip) = snippet_opt(cx, s) else { - // Assume true. This would require either an invalid span, or one which crosses file boundaries. - return true; - }; - let mut iter = tokenize_with_text(&snip); - - // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { - matches!( - t, - TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } - ) - }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) - { - return true; - } - } - false -} diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index b5870d94d99..78973984fb0 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -72,7 +72,7 @@ fn find_match_true<'tcx>( pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, span: Span, - message: &str, + message: &'static str, ) { if let PatKind::Lit(lit) = pat.kind && let ExprKind::Lit(lit) = lit.kind @@ -98,7 +98,7 @@ fn find_match_true<'tcx>( span, message, "consider using the condition directly", - sugg.to_string(), + sugg.into_string(), applicability, ); } @@ -227,7 +227,7 @@ fn find_method_sugg_for_if_let<'tcx>( cx, REDUNDANT_PATTERN_MATCHING, let_pat.span, - &format!("redundant pattern matching, consider using `{good_method}`"), + format!("redundant pattern matching, consider using `{good_method}`"), |diag| { // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op cx, REDUNDANT_PATTERN_MATCHING, span, - &format!("redundant pattern matching, consider using `{good_method}`"), + format!("redundant pattern matching, consider using `{good_method}`"), "try", sugg, Applicability::MachineApplicable, diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 1cdb7921f81..578aa7989e7 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -193,7 +193,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< cx, MEM_REPLACE_WITH_DEFAULT, expr_span, - &format!( + format!( "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`" ), |diag| { diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 08bfa2e009b..fb440ce656e 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -84,7 +84,7 @@ pub(crate) trait BindInsteadOfMap { "{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME ); - span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, "try", note, app); + span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, "try", note, app); true } else { false @@ -114,7 +114,7 @@ pub(crate) trait BindInsteadOfMap { } else { return false; }; - span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| { + span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, |diag| { multispan_sugg_with_applicability( diag, "try", @@ -157,7 +157,7 @@ pub(crate) trait BindInsteadOfMap { cx, BIND_INSTEAD_OF_MAP, expr.span, - &msg, + msg, "use the expression directly", snippet(cx, recv.span, "..").into(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs index baafb7030aa..a82abc79f2a 100644 --- a/clippy_lints/src/methods/bytes_nth.rs +++ b/clippy_lints/src/methods/bytes_nth.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, parent.span, - &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), + format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes()[{n}]",), applicability, @@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, expr.span, - &format!("called `.bytes().nth()` on a `{caller_type}`"), + format!("called `.bytes().nth()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes().get({n}).copied()"), applicability, diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index c99cec067bf..4ae0aeea2d1 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -30,7 +30,7 @@ pub(super) fn check( cx, lint, info.expr.span, - &format!("you should use the `{suggest}` method"), + format!("you should use the `{suggest}` method"), "like this", format!( "{}{}.{suggest}({})", diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index d07e45434a7..9c45ec2e56c 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -23,7 +23,7 @@ pub(super) fn check( cx, lint, info.expr.span, - &format!("you should use the `{suggest}` method"), + format!("you should use the `{suggest}` method"), "like this", format!( "{}{}.{suggest}('{}')", diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs index 67ad58d5a8c..5389861245a 100644 --- a/clippy_lints/src/methods/clear_with_drain.rs +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_range_full; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -28,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span } } -fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, expr: &Expr<'_>, types: &[rustc_span::Symbol]) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) // String type is a lang item but not a diagnostic item for now so we need a separate check @@ -44,7 +43,7 @@ fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { cx, CLEAR_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain` used to clear a `{ty_name}`"), + format!("`drain` used to clear a `{ty_name}`"), "try", "clear()".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 3e099004c47..4e6823e8220 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -94,7 +94,7 @@ pub(super) fn check( cx, CLONE_ON_COPY, expr.span, - &with_forced_trimmed_paths!(format!( + with_forced_trimmed_paths!(format!( "using `clone` on type `{ty}` which implements the `Copy` trait" )), help, diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs index 3a8ca37610a..56171a13452 100644 --- a/clippy_lints/src/methods/drain_collect.rs +++ b/clippy_lints/src/methods/drain_collect.rs @@ -70,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re cx, DRAIN_COLLECT, expr.span, - &format!("you seem to be trying to move all elements into a new `{typename}`"), + format!("you seem to be trying to move all elements into a new `{typename}`"), "consider using `mem::take`", sugg, Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 4d8fb217f7f..fba76852344 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -142,7 +142,7 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("unwrap_or_else({closure_args} panic!({sugg}))"), applicability, @@ -160,7 +160,7 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"), applicability, diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs index b05361ab212..eab536b88a5 100644 --- a/clippy_lints/src/methods/filetype_is_file.rs +++ b/clippy_lints/src/methods/filetype_is_file.rs @@ -34,5 +34,5 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr } let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files"); let help_msg = format!("use `{help_unary}FileType::is_dir()` instead"); - span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); + span_lint_and_help(cx, FILETYPE_IS_FILE, span, lint_msg, None, help_msg); } diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 9b656531957..581e3b308c3 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -16,20 +16,18 @@ use std::borrow::Cow; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; -fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { +fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool { match &expr.kind { - hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, - hir::ExprKind::Path(QPath::Resolved(_, segments)) => { - segments.segments.last().unwrap().ident.name == method_name - }, - hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, + ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name, + ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, + ExprKind::Closure(&Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { + ExprKind::MethodCall(PathSegment { ident, .. }, receiver, ..) => { if ident.name == method_name - && let hir::ExprKind::Path(path) = &receiver.kind + && let ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) && !body.params.is_empty() { @@ -45,10 +43,10 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> } } -fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { +fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } -fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { +fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok)) } @@ -267,10 +265,10 @@ impl<'tcx> OffendingFilterExpr<'tcx> { /// is `filter(|x| x.is_some()).map(|x| x.unwrap())` fn is_filter_some_map_unwrap( cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_recv: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, + expr: &Expr<'_>, + filter_recv: &Expr<'_>, + filter_arg: &Expr<'_>, + map_arg: &Expr<'_>, ) -> bool { let iterator = is_trait_method(cx, expr, sym::Iterator); let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::Option); @@ -279,12 +277,7 @@ fn is_filter_some_map_unwrap( } /// is `filter(|x| x.is_ok()).map(|x| x.unwrap())` -fn is_filter_ok_map_unwrap( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, -) -> bool { +fn is_filter_ok_map_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { // result has no filter, so we only check for iterators let iterator = is_trait_method(cx, expr, sym::Iterator); iterator && is_ok_filter_map(cx, filter_arg, map_arg) @@ -294,12 +287,12 @@ fn is_filter_ok_map_unwrap( #[allow(clippy::too_many_arguments)] pub(super) fn check( cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_recv: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, + expr: &Expr<'_>, + filter_recv: &Expr<'_>, + filter_arg: &Expr<'_>, filter_span: Span, - map_recv: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, + map_recv: &Expr<'_>, + map_arg: &Expr<'_>, map_span: Span, is_find: bool, ) { @@ -393,7 +386,7 @@ pub(super) fn check( ) }, }; - span_lint_and_then(cx, lint, span, &msg, |diag| { + span_lint_and_then(cx, lint, span, msg, |diag| { diag.span_suggestion(span, "try", sugg, applicability); if let Some((note, span)) = note_and_span { @@ -405,9 +398,9 @@ pub(super) fn check( fn is_find_or_filter<'a>( cx: &LateContext<'a>, - map_recv: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, + map_recv: &Expr<'_>, + filter_arg: &Expr<'_>, + map_arg: &Expr<'_>, ) -> Option<(Ident, CheckResult<'a>)> { if is_trait_method(cx, map_recv, sym::Iterator) // filter(|x| ...is_some())... diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 8291c373f37..999df875c75 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; +use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -7,8 +7,20 @@ use rustc_span::{sym, Span}; use super::FILTER_MAP_IDENTITY; +fn is_identity(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Applicability> { + if is_expr_untyped_identity_function(cx, expr) { + return Some(Applicability::MachineApplicable); + } + if is_expr_identity_function(cx, expr) { + return Some(Applicability::Unspecified); + } + None +} + pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) + && let Some(applicability) = is_identity(cx, filter_map_arg) + { span_lint_and_sugg( cx, FILTER_MAP_IDENTITY, @@ -16,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: "use of `filter_map` with an identity function", "try", "flatten()".to_string(), - Applicability::MachineApplicable, + applicability, ); } } diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs index 55fcf372894..f4465e654c2 100644 --- a/clippy_lints/src/methods/get_first.rs +++ b/clippy_lints/src/methods/get_first.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( cx, GET_FIRST, expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), + format!("accessing first element with `{slice_name}.get(0)`"), "try", format!("{slice_name}.first()"), app, @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( cx, GET_FIRST, expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), + format!("accessing first element with `{slice_name}.get(0)`"), "try", format!("{slice_name}.front()"), app, diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs index 3bdc154df04..62037651134 100644 --- a/clippy_lints/src/methods/get_last_with_len.rs +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -44,7 +44,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: cx, GET_LAST_WITH_LEN, expr.span, - &format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"), + format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"), "try", format!("{recv_snippet}.{method}()"), applicability, diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index afdcb3b6549..455274a4428 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -70,7 +70,7 @@ pub(super) fn check<'tcx>( cx, GET_UNWRAP, span, - &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), + format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), "try", format!( "{borrow_str}{}[{get_args_str}]", diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 78a553eb8c0..c510cd915d0 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -27,7 +27,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv cx, IMPLICIT_CLONE, expr.span, - &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), + format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), "consider using", if ref_count > 1 { format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1)) diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index efc3ddd20b4..230a8eb2ec4 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -32,7 +32,7 @@ pub fn check( cx, INEFFICIENT_TO_STRING, expr.span, - &format!("calling `to_string` on `{arg_ty}`"), + format!("calling `to_string` on `{arg_ty}`"), |diag| { diag.help(format!( "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index 80160d17c82..bbc7ce8d78a 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -27,7 +27,7 @@ pub(super) fn check( cx, INTO_ITER_ON_REF, method_span, - &format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",), + format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",), "call directly", method_name.to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/is_digit_ascii_radix.rs b/clippy_lints/src/methods/is_digit_ascii_radix.rs index e963950960a..210e4ae0a7b 100644 --- a/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( cx, IS_DIGIT_ASCII_RADIX, expr.span, - &format!("use of `char::is_digit` with literal radix of {num}"), + format!("use of `char::is_digit` with literal radix of {num}"), "try", format!( "{}.{replacement}()", diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs index 7fe66062251..d921b7ea14f 100644 --- a/clippy_lints/src/methods/is_empty.rs +++ b/clippy_lints/src/methods/is_empty.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ cx, CONST_IS_EMPTY, expr.span, - &format!("this expression always evaluates to {init_is_empty:?}"), + format!("this expression always evaluates to {init_is_empty:?}"), ); } } diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs index dd741cd43f9..49de83885a1 100644 --- a/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/clippy_lints/src/methods/iter_cloned_collect.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir: cx, ITER_CLONED_COLLECT, to_replace, - &format!( + format!( "called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ more readable" ), diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index bcddc7c786a..209cf2fcc0a 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -37,7 +37,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, ITER_COUNT, expr.span, - &format!("called `.{iter_method}().count()` on a `{caller_type}`"), + format!("called `.{iter_method}().count()` on a `{caller_type}`"), "try", format!( "{}.len()", diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs index 9f84321ced4..12647ea1ffc 100644 --- a/clippy_lints/src/methods/iter_filter.rs +++ b/clippy_lints/src/methods/iter_filter.rs @@ -55,7 +55,7 @@ fn is_method( } } match expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { + ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { // compare the identifier of the receiver to the parameter // we are in a filter => closure has a single parameter and a single, non-block // expression, this means that the parameter shadows all outside variables with @@ -73,7 +73,7 @@ fn is_method( // This is used to check for complete paths via `|a| std::option::Option::is_some(a)` // this then unwraps to a path with `QPath::TypeRelative` // we pass the params as they've been passed to the current call through the closure - hir::ExprKind::Call(expr, [param]) => { + ExprKind::Call(expr, [param]) => { // this will hit the `QPath::TypeRelative` case and check that the method name is correct if is_method(cx, expr, type_symbol, method_name, params) // we then check that this is indeed passing the parameter of the closure @@ -85,7 +85,7 @@ fn is_method( } false }, - hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => { + ExprKind::Path(QPath::TypeRelative(ty, mname)) => { let ty = cx.typeck_results().node_type(ty.hir_id); if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol) && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def() @@ -94,7 +94,7 @@ fn is_method( } false }, - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); let params = body.params.iter().map(|param| param.pat).collect::<Vec<_>>(); @@ -107,8 +107,8 @@ fn is_method( fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { if let Some(expr) = get_parent_expr(cx, expr) && is_trait_method(cx, expr, sym::Iterator) - && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind - && path.ident.name == rustc_span::sym::map + && let ExprKind::MethodCall(path, _, _, _) = expr.kind + && path.ident.name == sym::map { return true; } @@ -148,7 +148,7 @@ fn expression_type( { return None; } - if let hir::ExprKind::MethodCall(_, receiver, _, _) = expr.kind + if let ExprKind::MethodCall(_, receiver, _, _) = expr.kind && let receiver_ty = cx.typeck_results().expr_ty(receiver) && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty) { diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 1431a5db2d9..b9fec0c4f80 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {replacement_kind}s"), + format!("iterating on a map's {replacement_kind}s"), "try", format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"), applicability, @@ -64,7 +64,7 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {replacement_kind}s"), + format!("iterating on a map's {replacement_kind}s"), "try", format!( "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index 5b0b70b4b96..e31fa2f777d 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -28,7 +28,7 @@ pub(super) fn check<'tcx>( cx, ITER_NTH, expr.span, - &format!("called `.{iter_method}().nth()` on a {caller_type}"), + format!("called `.{iter_method}().nth()` on a {caller_type}"), |diag| { let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" }; diag.span_suggestion_verbose( diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 19b7e97339d..6c9bdcff826 100644 --- a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -69,7 +69,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re cx, ITER_ON_SINGLE_ITEMS, expr.span, - &format!("`{method_name}` call on a collection with only one item"), + format!("`{method_name}` call on a collection with only one item"), "try", sugg, Applicability::MaybeIncorrect, @@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re cx, ITER_ON_EMPTY_COLLECTIONS, expr.span, - &format!("`{method_name}` call on an empty collection"), + format!("`{method_name}` call on an empty collection"), "try", format!("{top_crate}::iter::empty()"), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index b2fe129cd95..4729481320e 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>( } if let Op::NeedlessMove(expr) = op { - let rustc_hir::ExprKind::Closure(closure) = expr.kind else { + let ExprKind::Closure(closure) = expr.kind else { return; }; let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 2ab721ace84..1378a07cbc4 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span cx, ITER_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain(..)` used on a `{ty_name}`"), + format!("`drain(..)` used on a `{ty_name}`"), "try", "into_iter()".to_string(), Applicability::MaybeIncorrect, diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index bf437db7e72..9e3b313156e 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -50,7 +50,7 @@ pub fn check( super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - &format!("consider using `saturating_{arith}`"), + format!("consider using `saturating_{arith}`"), format!( "{}.saturating_{arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index c3c7a3a0033..0901268e9bd 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function}; use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(closure_body.value); match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => { + hir::PatKind::Ref(inner, Mutability::Not) => { if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind { if ident_eq(name, closure_expr) { lint_explicit_closure(cx, e.span, recv.span, true, msrv); @@ -124,6 +124,7 @@ fn handle_path( && let ty::Ref(_, ty, Mutability::Not) = ty.kind() && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind() && lst.iter().all(|l| l.as_type() == Some(*ty)) + && !should_call_clone_as_function(cx, *ty) { lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); } @@ -160,7 +161,7 @@ fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { MAP_CLONE, replace, "you are explicitly cloning with `.map()`", - &format!("consider calling the dedicated `{replacement}` method"), + format!("consider calling the dedicated `{replacement}` method"), format!( "{}.{replacement}()", snippet_with_applicability(cx, root, "..", &mut applicability), @@ -183,7 +184,7 @@ fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_cop MAP_CLONE, replace, message, - &format!("consider calling the dedicated `{sugg_method}` method"), + format!("consider calling the dedicated `{sugg_method}` method"), format!( "{}.{sugg_method}()", snippet_with_applicability(cx, root, "..", &mut applicability), diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs index 26ef0d10fed..def8be2ef73 100644 --- a/clippy_lints/src/methods/map_flatten.rs +++ b/clippy_lints/src/methods/map_flatten.rs @@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_ cx, MAP_FLATTEN, expr.span.with_lo(map_span.lo()), - &format!("called `map(..).flatten()` on `{caller_ty_name}`"), - &format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), + format!("called `map(..).flatten()` on `{caller_ty_name}`"), + format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), format!("{method_to_use}({closure_snippet})"), applicability, ); diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs index 6da9a87f5ee..5dd7b1b02ad 100644 --- a/clippy_lints/src/methods/map_identity.rs +++ b/clippy_lints/src/methods/map_identity.rs @@ -29,7 +29,7 @@ pub(super) fn check( MAP_IDENTITY, sugg_span, "unnecessary map of the identity function", - &format!("remove the call to `{name}`"), + format!("remove the call to `{name}`"), String::new(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b6c474212cd..2fb317c8c68 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -231,8 +231,12 @@ declare_clippy_lint! { /// used instead. /// /// ### Why is this bad? - /// When applicable, `filter_map()` is more clear since it shows that - /// `Option` is used to produce 0 or 1 items. + /// `filter_map()` is known to always produce 0 or 1 output items per input item, + /// rather than however many the inner iterator type produces. + /// Therefore, it maintains the upper bound in `Iterator::size_hint()`, + /// and communicates to the reader that the input items are not being expanded into + /// multiple output items without their having to notice that the mapping function + /// returns an `Option`. /// /// ### Example /// ```no_run @@ -2998,13 +3002,22 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Looks for calls to `<Box<dyn Any> as Any>::type_id`. + /// Looks for calls to `.type_id()` on a `Box<dyn _>`. /// /// ### Why is this bad? - /// This most certainly does not do what the user expects and is very easy to miss. - /// Calling `type_id` on a `Box<dyn Any>` calls `type_id` on the `Box<..>` itself, - /// so this will return the `TypeId` of the `Box<dyn Any>` type (not the type id - /// of the value referenced by the box!). + /// This almost certainly does not do what the user expects and can lead to subtle bugs. + /// Calling `.type_id()` on a `Box<dyn Trait>` returns a fixed `TypeId` of the `Box` itself, + /// rather than returning the `TypeId` of the underlying type behind the trait object. + /// + /// For `Box<dyn Any>` specifically (and trait objects that have `Any` as its supertrait), + /// this lint will provide a suggestion, which is to dereference the receiver explicitly + /// to go from `Box<dyn Any>` to `dyn Any`. + /// This makes sure that `.type_id()` resolves to a dynamic call on the trait object + /// and not on the box. + /// + /// If the fixed `TypeId` of the `Box` is the intended behavior, it's better to be explicit about it + /// and write `TypeId::of::<Box<dyn Trait>>()`: + /// this makes it clear that a fixed `TypeId` is returned and not the `TypeId` of the implementor. /// /// ### Example /// ```rust,ignore @@ -3024,7 +3037,7 @@ declare_clippy_lint! { #[clippy::version = "1.73.0"] pub TYPE_ID_ON_BOX, suspicious, - "calling `.type_id()` on `Box<dyn Any>`" + "calling `.type_id()` on a boxed trait object" } declare_clippy_lint! { @@ -4236,8 +4249,8 @@ impl_lint_pass!(Methods => [ /// Extracts a method call name, args, and `Span` of the method name. pub fn method_call<'tcx>( - recv: &'tcx hir::Expr<'tcx>, -) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> { + recv: &'tcx Expr<'tcx>, +) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind { if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { let name = path.ident.name.as_str(); @@ -4248,7 +4261,7 @@ pub fn method_call<'tcx>( } impl<'tcx> LateLintPass<'tcx> for Methods { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.from_expansion() { return; } @@ -4256,12 +4269,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { self.check_methods(cx, expr); match expr.kind { - hir::ExprKind::Call(func, args) => { + ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); unnecessary_fallible_conversions::check_function(cx, expr, func); manual_c_str_literals::check(cx, expr, func, args, &self.msrv); }, - hir::ExprKind::MethodCall(method_call, receiver, args, _) => { + ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); @@ -4273,7 +4286,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv); }, - hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { + ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { expr, chain: lhs, @@ -4320,12 +4333,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, - &format!( + format!( "method `{}` can be confused for the standard trait method `{}::{}`", method_config.method_name, method_config.trait_name, method_config.method_name ), None, - &format!( + format!( "consider implementing the trait `{}` or choosing a less ambiguous method name", method_config.trait_name ), @@ -4995,9 +5008,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { - expr: &'a hir::Expr<'a>, - chain: &'a hir::Expr<'a>, - other: &'a hir::Expr<'a>, + expr: &'a Expr<'a>, + chain: &'a Expr<'a>, + other: &'a Expr<'a>, eq: bool, } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 9e2fd92255e..662e7746496 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -107,7 +107,7 @@ pub(super) fn check<'tcx>( span.push_span_label(iter_call.span, "the iterator could be used here instead"); span_lint_hir_and_then( cx, - super::NEEDLESS_COLLECT, + NEEDLESS_COLLECT, collect_expr.hir_id, span, NEEDLESS_COLLECT_MSG, diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index 77484ab91a9..d425b505a76 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, S cx, NONSENSICAL_OPEN_OPTIONS, prev_span, - &format!("the method `{}` is called more than once", &option), + format!("the method `{}` is called more than once", &option), ); } } diff --git a/clippy_lints/src/methods/option_as_ref_cloned.rs b/clippy_lints/src/methods/option_as_ref_cloned.rs index d7fec360fa2..ba167f9d9c2 100644 --- a/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_s cx, OPTION_AS_REF_CLONED, as_ref_ident_span.to(cloned_ident_span), - &format!("cloning an `Option<_>` using `.{method}().cloned()`"), + format!("cloning an `Option<_>` using `.{method}().cloned()`"), "this can be written more concisely by cloning the `Option<_>` directly", "clone".into(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 88e2af15658..cb57689b0c4 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -104,8 +104,8 @@ pub(super) fn check( cx, OPTION_AS_REF_DEREF, expr.span, - &msg, - &suggestion, + msg, + suggestion, hint, Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index ab36f854fcb..efec9dd716d 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( } else { "map_or(<a>, <f>)" }; - let msg = &format!("called `map(<f>).unwrap_or({arg})` on an `Option` value"); + let msg = format!("called `map(<f>).unwrap_or({arg})` on an `Option` value"); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_arg.span; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 0602eeaa704..583e04fb4b1 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( cx, UNWRAP_OR_DEFAULT, method_span.with_hi(span.hi()), - &format!("use of `{name}` to construct default value"), + format!("use of `{name}` to construct default value"), "try", format!("{sugg}()"), Applicability::MachineApplicable, @@ -167,7 +167,7 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("{name}_{suffix}({sugg})"), app, diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 1148628b084..28ca76832eb 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' cx, RANGE_ZIP_WITH_LEN, expr.span, - &format!( + format!( "it is more idiomatic to use `{}.iter().enumerate()`", snippet(cx, recv.span, "_") ), diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ef1baa6c988..ac5cc2f01e5 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( && let closure_body = cx.tcx.hir().body(body) && let Some(closure_arg) = closure_body.params.first() { - if let hir::PatKind::Ref(..) = closure_arg.pat.kind { + if let PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { // `find()` provides a reference to the item, but `any` does not, @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "consider using", format!( "any({})", @@ -76,7 +76,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, expr.span, - &msg, + msg, "consider using", format!( "!{iter}.any({})", @@ -94,7 +94,7 @@ pub(super) fn check<'tcx>( "" } ); - span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, &hint); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, msg, None, hint); } } // lint if `find()` is called by `String` or `&str` @@ -117,7 +117,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "consider using", format!("contains({find_arg})"), applicability, @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, expr.span, - &msg, + msg, "consider using", format!("!{string}.contains({find_arg})"), applicability, diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs index 0f4c97022db..aef14435d8a 100644 --- a/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx cx, STABLE_SORT_PRIMITIVE, e.span, - &format!("used `sort` on primitive type `{slice_type}`"), + format!("used `sort` on primitive type `{slice_type}`"), |diag| { let mut app = Applicability::MachineApplicable; let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 946cdb49d27..55ae9746298 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -53,7 +53,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_ cx, NEEDLESS_SPLITN, expr.span, - &format!("unnecessary use of `{r}splitn`"), + format!("unnecessary use of `{r}splitn`"), "try", format!( "{}.{r}split({})", @@ -154,7 +154,7 @@ fn check_manual_split_once_indirect( let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; - span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| { + span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, msg, |diag| { diag.span_label(first.span, "first usage here"); diag.span_label(second.span, "second usage here"); diff --git a/clippy_lints/src/methods/suspicious_splitn.rs b/clippy_lints/src/methods/suspicious_splitn.rs index c45212581ee..ff5c1d1a401 100644 --- a/clippy_lints/src/methods/suspicious_splitn.rs +++ b/clippy_lints/src/methods/suspicious_splitn.rs @@ -37,6 +37,6 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se ) }; - span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, &msg, None, note_msg); + span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, msg, None, note_msg); } } diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs index 60864902a48..ce7aefed01f 100644 --- a/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -23,7 +23,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &with_forced_trimmed_paths!(format!( + with_forced_trimmed_paths!(format!( "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), |diag| { diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs index 4917936a932..6f9b38fcf83 100644 --- a/clippy_lints/src/methods/type_id_on_box.rs +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -5,13 +5,33 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self, ExistentialPredicate, Ty}; use rustc_span::{sym, Span}; -fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { +/// Checks if the given type is `dyn Any`, or a trait object that has `Any` as a supertrait. +/// Only in those cases will its vtable have a `type_id` method that returns the implementor's +/// `TypeId`, and only in those cases can we give a proper suggestion to dereference the box. +/// +/// If this returns false, then `.type_id()` likely (this may have FNs) will not be what the user +/// expects in any case and dereferencing it won't help either. It will likely require some +/// other changes, but it is still worth emitting a lint. +/// See <https://github.com/rust-lang/rust-clippy/pull/11350#discussion_r1544863005> for more details. +fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if let ty::Dynamic(preds, ..) = ty.kind() { preds.iter().any(|p| match p.skip_binder() { - ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id), + ExistentialPredicate::Trait(tr) => { + cx.tcx.is_diagnostic_item(sym::Any, tr.def_id) + || cx + .tcx + .super_predicates_of(tr.def_id) + .predicates + .iter() + .any(|(clause, _)| { + matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(super_tr) + if cx.tcx.is_diagnostic_item(sym::Any, super_tr.def_id())) + }) + }, _ => false, }) } else { @@ -26,36 +46,42 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) && let ty::Ref(_, ty, _) = recv_ty.kind() && let ty::Adt(adt, args) = ty.kind() && adt.is_box() - && is_dyn_any(cx, args.type_at(0)) + && let inner_box_ty = args.type_at(0) + && let ty::Dynamic(..) = inner_box_ty.kind() { + let ty_name = with_forced_trimmed_paths!(ty.to_string()); + span_lint_and_then( cx, TYPE_ID_ON_BOX, call_span, - "calling `.type_id()` on a `Box<dyn Any>`", + format!("calling `.type_id()` on `{ty_name}`"), |diag| { let derefs = recv_adjusts .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(None))) .count(); - let mut sugg = "*".repeat(derefs + 1); - sugg += &snippet(cx, receiver.span, "<expr>"); - diag.note( - "this returns the type id of the literal type `Box<dyn Any>` instead of the \ + "this returns the type id of the literal type `Box<_>` instead of the \ type id of the boxed value, which is most likely not what you want", ) - .note( - "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \ - which makes it more clear", - ) - .span_suggestion( - receiver.span, - "consider dereferencing first", - format!("({sugg})"), - Applicability::MaybeIncorrect, - ); + .note(format!( + "if this is intentional, use `TypeId::of::<{ty_name}>()` instead, \ + which makes it more clear" + )); + + if is_subtrait_of_any(cx, inner_box_ty) { + let mut sugg = "*".repeat(derefs + 1); + sugg += &snippet(cx, receiver.span, "<expr>"); + + diag.span_suggestion( + receiver.span, + "consider dereferencing first", + format!("({sugg})"), + Applicability::MaybeIncorrect, + ); + } }, ); } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index fabf3fa0c0c..daf99d98614 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a UNNECESSARY_FIND_MAP }, expr.span, - &format!("this `.{name}` can be written more simply using `.{sugg}`"), + format!("this `.{name}` can be written more simply using `.{sugg}`"), ); } } diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index cc8053ef507..f6184222d8e 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -58,7 +58,7 @@ pub(super) fn check( cx, UNNECESSARY_GET_THEN_CHECK, both_calls_span, - &format!("unnecessary use of `{snippet}`"), + format!("unnecessary use of `{snippet}`"), "replace it with", suggestion, Applicability::MaybeIncorrect, @@ -70,7 +70,7 @@ pub(super) fn check( cx, UNNECESSARY_GET_THEN_CHECK, both_calls_span, - &format!("unnecessary use of `{snippet}`"), + format!("unnecessary use of `{snippet}`"), |diag| { diag.span_suggestion( full_span, diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 36497d59a5a..520dcb2d52d 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -61,7 +61,7 @@ pub fn check_for_loop_iter( cx, UNNECESSARY_TO_OWNED, expr.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), |diag| { // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to // a `to_owned`-like function was removed, then the next suggestion may be diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 1b2bfbf4090..494d71fc053 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -63,7 +63,7 @@ pub(super) fn check( let help_message = format!("used `{method}()` on `{constructor}` value"); let suggestion_message = format!("remove the `{constructor}` and `{method}()`"); - span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| { let suggestions = match (constructor, method, ty) { ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), ("None", "expect", _) => Some(vec![ diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index e58d4776427..23fc323446e 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -18,8 +18,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ - self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, - TraitPredicate, Ty, + self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -138,7 +137,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!( "{:&>width$}{receiver_snippet}", @@ -163,7 +162,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", receiver_snippet, Applicability::MachineApplicable, @@ -173,7 +172,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "remove this", String::new(), Applicability::MachineApplicable, @@ -188,7 +187,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.as_ref()"), Applicability::MachineApplicable, @@ -232,7 +231,7 @@ fn check_into_iter_call_arg( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.iter().{cloned_or_copied}()"), Applicability::MaybeIncorrect, @@ -271,7 +270,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}{as_ref}.split({arg_snippet})"), Applicability::MaybeIncorrect, @@ -350,7 +349,7 @@ fn check_other_call_arg<'tcx>( cx, UNNECESSARY_TO_OWNED, maybe_arg.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{:&>n_refs$}{receiver_snippet}", ""), Applicability::MachineApplicable, @@ -642,7 +641,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx cx, UNNECESSARY_TO_OWNED, arg.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "replace it with", if original_arg_ty.is_array() { format!("{snippet}.as_slice()") diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 7bd16b473ce..516b8984ad7 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -69,7 +69,7 @@ pub(super) fn check( cx, variant.lint(), expr.span, - &format!("used `{}()` on {kind} value", variant.method_name(is_err)), + format!("used `{}()` on {kind} value", variant.method_name(is_err)), |diag| { diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic")); diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index b8baad18cc8..ae2b6e6347e 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::walk_ptrs_ty_depth; +use clippy_utils::ty::{should_call_clone_as_function, walk_ptrs_ty_depth}; use clippy_utils::{ get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs, }; @@ -68,7 +68,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, cx, USELESS_ASREF, expr.span, - &format!("this call to `{call_name}` does nothing"), + format!("this call to `{call_name}` does nothing"), "try", snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, @@ -93,6 +93,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, // And that it only has one argument. && let [arg] = args && is_calling_clone(cx, arg) + // And that we are not recommending recv.clone() over Arc::clone() or similar + && !should_call_clone_as_function(cx, rcv_ty) { lint_as_ref_clone(cx, expr.span.with_hi(parent.span.hi()), recvr, call_name); } @@ -157,7 +159,7 @@ fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, ca cx, USELESS_ASREF, span, - &format!("this call to `{call_name}.map(...)` does nothing"), + format!("this call to `{call_name}.map(...)` does nothing"), "try", format!( "{}.clone()", diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 3a0305b4d55..ef00c812d51 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -3,7 +3,6 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; use rustc_ast::ast; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat}; use rustc_lint::LateContext; @@ -13,9 +12,9 @@ use rustc_span::symbol::sym; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'tcx>, + expr: &'tcx Expr<'tcx>, ty: Ty<'tcx>, -) -> Option<&'tcx hir::Expr<'tcx>> { +) -> Option<&'tcx Expr<'tcx>> { fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { match ty.kind() { ty::Slice(_) => true, @@ -27,7 +26,7 @@ pub(super) fn derefs_to_slice<'tcx>( } } - if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind { + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind { if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) { Some(self_arg) } else { @@ -51,10 +50,10 @@ pub(super) fn derefs_to_slice<'tcx>( pub(super) fn get_hint_if_single_char_arg( cx: &LateContext<'_>, - arg: &hir::Expr<'_>, + arg: &Expr<'_>, applicability: &mut Applicability, ) -> Option<String> { - if let hir::ExprKind::Lit(lit) = &arg.kind + if let ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(r, style) = lit.node && let string = r.as_str() && string.chars().count() == 1 diff --git a/clippy_lints/src/methods/verbose_file_reads.rs b/clippy_lints/src/methods/verbose_file_reads.rs index 2fe5ae9a9ad..181b413a182 100644 --- a/clippy_lints/src/methods/verbose_file_reads.rs +++ b/clippy_lints/src/methods/verbose_file_reads.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, - (msg, help): (&str, &str), + (msg, help): (&'static str, &'static str), ) { if is_trait_method(cx, expr, sym::IoRead) && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _))) diff --git a/clippy_lints/src/methods/wrong_self_convention.rs b/clippy_lints/src/methods/wrong_self_convention.rs index 0a810a13f3f..28068c63473 100644 --- a/clippy_lints/src/methods/wrong_self_convention.rs +++ b/clippy_lints/src/methods/wrong_self_convention.rs @@ -137,7 +137,7 @@ pub(super) fn check<'tcx>( cx, WRONG_SELF_CONVENTION, first_arg_span, - &format!( + format!( "{suggestion} usually take {}", &self_kinds .iter() diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index 0016fb33517..c6b7f5b0ce2 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -181,7 +181,7 @@ fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str conf.min_ident_chars_threshold, )) }; - span_lint(cx, MIN_IDENT_CHARS, span, &help); + span_lint(cx, MIN_IDENT_CHARS, span, help); } /// Attempt to convert the node to an [`ItemKind::Use`] node. diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 11fecb7d72e..f5ce8dd29b1 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -246,7 +246,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { cx, USED_UNDERSCORE_BINDING, expr.span, - &format!( + format!( "used binding `{name}` which is prefixed with an underscore. A leading \ underscore signals that a binding will not be used" ), diff --git a/clippy_lints/src/misc_early/builtin_type_shadow.rs b/clippy_lints/src/misc_early/builtin_type_shadow.rs index 9f6b0bdc7a4..662f7cd8500 100644 --- a/clippy_lints/src/misc_early/builtin_type_shadow.rs +++ b/clippy_lints/src/misc_early/builtin_type_shadow.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) { cx, BUILTIN_TYPE_SHADOW, param.ident.span, - &format!("this generic shadows the built-in type `{}`", prim_ty.name()), + format!("this generic shadows the built-in type `{}`", prim_ty.name()), ); } } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs index eda4376f200..e0a5e401a50 100644 --- a/clippy_lints/src/misc_early/literal_suffix.rs +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi cx, SEPARATED_LITERAL_SUFFIX, lit_span, - &format!("{sugg_type} type suffix should not be separated by an underscore"), + format!("{sugg_type} type suffix should not be separated by an underscore"), "remove the underscore", format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), Applicability::MachineApplicable, @@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi cx, UNSEPARATED_LITERAL_SUFFIX, lit_span, - &format!("{sugg_type} type suffix should be separated by an underscore"), + format!("{sugg_type} type suffix should be separated by an underscore"), "add an underscore", format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), Applicability::MachineApplicable, diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index abe5b00e888..2f5499d7656 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -394,7 +394,7 @@ impl EarlyLintPass for MiscEarlyLints { cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondence, - &format!( + format!( "`{arg_name}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult" ), diff --git a/clippy_lints/src/misc_early/redundant_pattern.rs b/clippy_lints/src/misc_early/redundant_pattern.rs index d7bb0616acb..d5b5b2bf2dd 100644 --- a/clippy_lints/src/misc_early/redundant_pattern.rs +++ b/clippy_lints/src/misc_early/redundant_pattern.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { cx, REDUNDANT_PATTERN, pat.span, - &format!( + format!( "the `{} @ _` pattern can be written as just `{}`", ident.name, ident.name, ), diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 676e5d40bb7..cb305cf5582 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pat.span, "all the struct fields are matched to a wildcard pattern, consider using `..`", None, - &format!("try with `{type_name} {{ .. }}` instead"), + format!("try with `{type_name} {{ .. }}` instead"), ); return; } @@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` \ instead", None, - &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), + format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), ); } } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 0739b49fe19..0842a872824 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { "try `{}`, or a name that does not conflict with `{type_name}`'s generic params", type_param_names[i] ); - span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, &msg, None, &help); + span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, msg, None, help); } } } diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index 39d4ea74b31..c29e46b941c 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -65,7 +65,7 @@ declare_clippy_lint! { } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); -fn report_lint<F>(cx: &LateContext<'_>, full_span: Span, msg: &str, indexes: &[Span], f: F) +fn report_lint<F>(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: &[Span], f: F) where F: FnOnce(&mut Diag<'_, ()>), { diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 2773427e72d..2fb784dae1c 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -127,7 +127,7 @@ impl MissingDoc { cx, MISSING_DOCS_IN_PRIVATE_ITEMS, sp, - &format!("missing documentation for {article} {desc}"), + format!("missing documentation for {article} {desc}"), ); } } diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 3bf9f75e226..a64faa124f0 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -198,7 +198,7 @@ fn check_struct<'tcx>( } impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { // is this an `impl Debug for X` block? if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 7393b39c8f6..c6a76478806 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -64,7 +64,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, - &format!("missing `#[inline]` for {desc}"), + format!("missing `#[inline]` for {desc}"), ); } } diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index 6bbf18d52d1..6f844bc646a 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx, MISSING_TRAIT_METHODS, source_map.guess_head_span(item.span), - &format!("missing trait method provided by default: `{}`", assoc.name), + format!("missing trait method provided by default: `{}`", assoc.name), Some(definition_span), "implement the method", ); diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 656fb907fcd..181351910db 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -325,7 +325,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { self.cx, MIXED_READ_WRITE_IN_EXPRESSION, expr.span, - &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), + format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), Some(self.write_expr.span), "whether read occurs before this write depends on evaluation order", ); diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 0226b31dd19..6c031c08175 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -129,9 +129,9 @@ impl EarlyLintPass for ModStyle { cx, SELF_NAMED_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - &format!("`mod.rs` files are required, found `{}`", path.display()), + format!("`mod.rs` files are required, found `{}`", path.display()), None, - &format!("move `{}` to `{}`", path.display(), correct.display(),), + format!("move `{}` to `{}`", path.display(), correct.display(),), ); } } @@ -169,9 +169,9 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source cx, MOD_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - &format!("`mod.rs` files are not allowed, found `{}`", path.display()), + format!("`mod.rs` files are not allowed, found `{}`", path.display()), None, - &format!("move `{}` to `{}`", path.display(), mod_file.display()), + format!("move `{}` to `{}`", path.display(), mod_file.display()), ); } } diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 648d780ac09..0e138066780 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { cx, MULTIPLE_UNSAFE_OPS_PER_BLOCK, block.span, - &format!( + format!( "this `unsafe` block contains {} unsafe operations, expected only one", unsafe_ops.len() ), diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 14a1e6be738..6867f76a723 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args); check_arguments( cx, - std::iter::once(receiver).chain(arguments.iter()).collect(), + iter::once(receiver).chain(arguments.iter()).collect(), method_type, path.ident.as_str(), "method", @@ -83,14 +83,13 @@ fn check_arguments<'tcx>( let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in iter::zip(arguments, parameters) { match parameter.kind() { - ty::Ref(_, _, Mutability::Not) - | ty::RawPtr(_, Mutability::Not) => { + ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) => { if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind { span_lint( cx, UNNECESSARY_MUT_PASSED, argument.span, - &format!("the {fn_kind} `{name}` doesn't need a mutable reference"), + format!("the {fn_kind} `{name}` doesn't need a mutable reference"), ); } }, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 96cd81ecdf3..e92ba93942e 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { cx, DEBUG_ASSERT_WITH_MUT_CALL, span, - &format!("do not call a function with mutable arguments inside of `{macro_name}!`"), + format!("do not call a function with mutable arguments inside of `{macro_name}!`"), ); } } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 61243c83731..7ecc8617694 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -92,9 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { behavior and not the internal type, consider using `Mutex<()>`" ); match *mutex_param.kind() { - ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - ty::Int(t) if t != ty::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), + ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg), }; } } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 166a7f71d69..f9ee4a3dc93 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,11 +6,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - higher, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, + higher, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, span_extract_comment, + SpanlessEq, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -135,13 +136,6 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool { false } -fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { - matches!( - cx.tcx.parent_hir_node(id), - Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }) - ) -} - impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; @@ -323,11 +317,11 @@ fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr fn check_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, - left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>, + left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>, ) { if let ExprKind::Binary(op, left_side, right_side) = e.kind { let (l_ty, r_ty) = ( @@ -397,7 +391,7 @@ fn check_comparison<'a, 'tcx>( binop_span, m, "try simplifying it as shown", - h(left_side, right_side).to_string(), + h(left_side, right_side).into_string(), applicability, ); }), @@ -412,7 +406,7 @@ fn suggest_bool_comparison<'a, 'tcx>( span: Span, expr: &Expr<'_>, mut app: Applicability, - message: &str, + message: &'static str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app); @@ -422,7 +416,7 @@ fn suggest_bool_comparison<'a, 'tcx>( span, message, "try simplifying it as shown", - conv_hint(hint).to_string(), + conv_hint(hint).into_string(), app, ); } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 4710a69443b..d91329eadcb 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { fn check_subpatterns<'tcx>( cx: &LateContext<'tcx>, - message: &str, + message: &'static str, ref_pat: &Pat<'_>, pat: &Pat<'_>, subpatterns: impl IntoIterator<Item = &'tcx Pat<'tcx>>, diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index a32bca3d038..c555fc8675c 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -381,7 +381,7 @@ fn replace_types<'tcx>( fn_sig: FnSig<'tcx>, arg_index: usize, projection_predicates: &[ProjectionPredicate<'tcx>], - args: &mut [ty::GenericArg<'tcx>], + args: &mut [GenericArg<'tcx>], ) -> bool { let mut replaced = BitSet::new_empty(args.len()); @@ -399,7 +399,7 @@ fn replace_types<'tcx>( return false; } - args[param_ty.index as usize] = ty::GenericArg::from(new_ty); + args[param_ty.index as usize] = GenericArg::from(new_ty); // The `replaced.insert(...)` check provides some protection against infinite loops. if replaced.insert(param_ty.index) { @@ -414,7 +414,7 @@ fn replace_types<'tcx>( )); if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) - && args[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty) + && args[term_param_ty.index as usize] != GenericArg::from(projected_ty) { deque.push_back((*term_param_ty, projected_ty)); } diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index ff72b5e69ef..8b4a12bb766 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -313,7 +313,7 @@ fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: L expr.span, message, None, - &format!("{header}\n{snip}"), + format!("{header}\n{snip}"), ); } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index d7adf22ff32..37463cfec9a 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -131,7 +131,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { NEEDLESS_QUESTION_MARK, expr.span, "question mark operator is useless here", - &format!("try removing question mark and `{sugg_remove}`"), + format!("try removing question mark and `{sugg_remove}`"), format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 627b4968d9f..78dd1e05162 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -134,9 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { NEW_WITHOUT_DEFAULT, id.into(), impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{self_type_snip}`" - ), + format!("you should consider adding a `Default` implementation for `{self_type_snip}`"), |diag| { diag.suggest_prepend_item( cx, diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 43810ec0ec7..f915145e794 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { } } - fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(def_id) = path_to_local(expr) { // FIXME(rust/#120456) - is `swap_remove` correct? self.underscore_bindings.swap_remove(&def_id); diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 6cb84bb78b6..73fc34c2450 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -285,7 +285,7 @@ impl NonCopyConst { let def_id = body_id.hir_id.owner.to_def_id(); let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); let instance = ty::Instance::new(def_id, args); - let cid = rustc_middle::mir::interpret::GlobalId { + let cid = GlobalId { instance, promoted: None, }; @@ -534,7 +534,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } } -fn ignored_macro(cx: &LateContext<'_>, it: &rustc_hir::Item<'_>) -> bool { +fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool { macro_backtrace(it.span).any(|macro_call| { matches!( cx.tcx.get_diagnostic_name(macro_call.def_id), diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index b8c3c7fa65a..7b26235291a 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { self.cx, MANY_SINGLE_CHAR_NAMES, span, - &format!("{num_single_char_names} bindings with single-character names in scope"), + format!("{num_single_char_names} bindings with single-character names in scope"), ); } } diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 408216229a4..74e6c57b52d 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { cx, NON_SEND_FIELDS_IN_SEND_TY, item.span, - &format!( + format!( "some fields in `{}` are not safe to be sent to another thread", snippet(cx, hir_impl.self_ty.span, "Unknown") ), diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 1c6069e9c65..88f2eabaccb 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -121,7 +121,7 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), spa cx, NONSTANDARD_MACRO_BRACES, span, - &format!("use of irregular braces for `{macro_name}!` macro"), + format!("use of irregular braces for `{macro_name}!` macro"), "consider writing", format!("{macro_name}!{open}{macro_args}{close}"), Applicability::MachineApplicable, diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 8822dfeeddd..2fc039ae886 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -94,7 +94,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { cx, OCTAL_ESCAPES, span, - &format!( + format!( "octal-looking escape in {} literal", if is_string { "string" } else { "byte string" } ), diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs index f4863600ccc..9769da6d3e9 100644 --- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( } ); - span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); + span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, help); } } diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs index 2e026c369ee..545e680ce0d 100644 --- a/clippy_lints/src/operators/bit_mask.rs +++ b/clippy_lints/src/operators/bit_mask.rs @@ -64,7 +64,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), ); } } else if mask_value == 0 { @@ -77,7 +77,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), ); } }, @@ -90,7 +90,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -102,7 +102,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), ); } else { check_ineffective_lt(cx, span, mask_value, cmp_value, "|"); @@ -118,7 +118,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -130,7 +130,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), ); } else { check_ineffective_gt(cx, span, mask_value, cmp_value, "|"); @@ -149,7 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), + format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } @@ -160,7 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), + format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index e278cf9835a..7bf9b8ef866 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -89,7 +89,7 @@ pub(super) fn check<'tcx>( span, "left-hand side of `&&` operator has no effect", Some(left_cond.span.until(right_cond.span)), - &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), + format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), ); } else { span_lint_and_note( @@ -98,7 +98,7 @@ pub(super) fn check<'tcx>( span, "right-hand side of `&&` operator has no effect", Some(and_op.span.to(right_cond.span)), - &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), + format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), ); } // We could autofix this error but choose not to, @@ -124,7 +124,7 @@ pub(super) fn check<'tcx>( span, "boolean expression will never evaluate to 'true'", None, - ¬e, + note, ); }; } diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index f120be13836..ca3112ce5c4 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -31,7 +31,7 @@ pub(crate) fn check<'tcx>( cx, DURATION_SUBSEC, expr.span, - &format!("calling `{suggested_fn}()` is more concise than this calculation"), + format!("calling `{suggested_fn}()` is more concise than this calculation"), "try", format!( "{}.{suggested_fn}()", diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 01dd418c38b..1421893274f 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -24,7 +24,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { cx, EQ_OP, lhs.span.to(rhs.span), - &format!("identical args used in this `{macro_name}!` macro call"), + format!("identical args used in this `{macro_name}!` macro call"), ); } } @@ -41,7 +41,7 @@ pub(crate) fn check<'tcx>( cx, EQ_OP, e.span, - &format!("equal expressions as operands to `{}`", op.as_str()), + format!("equal expressions as operands to `{}`", op.as_str()), |diag| { if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs index 2a933a11e12..c56518ac72a 100644 --- a/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/clippy_lints/src/operators/modulo_arithmetic.rs @@ -113,7 +113,7 @@ fn check_const_operands<'tcx>( cx, MODULO_ARITHMETIC, expr.span, - &format!( + format!( "you are using modulo operator on constants with different signs: `{} % {}`", lhs_operand.string_representation.as_ref().unwrap(), rhs_operand.string_representation.as_ref().unwrap() diff --git a/clippy_lints/src/operators/ptr_eq.rs b/clippy_lints/src/operators/ptr_eq.rs index a69989e400b..607930561e0 100644 --- a/clippy_lints/src/operators/ptr_eq.rs +++ b/clippy_lints/src/operators/ptr_eq.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( cx, PTR_EQ, expr.span, - &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), + format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, diff --git a/clippy_lints/src/operators/self_assignment.rs b/clippy_lints/src/operators/self_assignment.rs index 7c9d5320a3a..a932378fbb5 100644 --- a/clippy_lints/src/operators/self_assignment.rs +++ b/clippy_lints/src/operators/self_assignment.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx cx, SELF_ASSIGNMENT, e.span, - &format!("self-assignment of `{rhs}` to `{lhs}`"), + format!("self-assignment of `{rhs}` to `{lhs}`"), ); } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 556c493d36c..3cbd03a58c5 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -304,7 +304,7 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { cx, OPTION_IF_LET_ELSE, expr.span, - format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(), + format!("use Option::{} instead of an if let/else", det.method_sugg), "try", format!( "{}.{}({}, {})", diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index ec03ab0e41a..bb4a1de9f77 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -206,7 +206,7 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!( + format!( "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size ), @@ -236,7 +236,7 @@ impl<'tcx> PassByRefOrValue { cx, LARGE_TYPES_PASSED_BY_VALUE, input.span, - &format!( + format!( "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size ), diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index 127801de7de..44db061b8be 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -1,5 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{ + intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; @@ -138,7 +140,7 @@ fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible span, "type of pattern does not match the expression type", None, - &format!( + format!( "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings", match (deref_possible, level) { (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ", diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 896c99a7104..83b32000a9f 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { ) .filter(|arg| arg.mutability() == Mutability::Not) { - span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, &arg.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, arg.build_msg(), |diag| { diag.span_suggestion( arg.span, "change this to", @@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { let results = check_ptr_arg_usage(cx, body, &lint_args); for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { - span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, &args.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| { diag.multipart_suggestion( "change this to", iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx)))) @@ -628,7 +628,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } }, ExprKind::MethodCall(name, self_arg, expr_args, _) => { - let i = std::iter::once(self_arg) + let i = iter::once(self_arg) .chain(expr_args.iter()) .position(|arg| arg.hir_id == child_id) .unwrap_or(0); diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index ff8ec2ad57c..7c82895d609 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -64,13 +64,13 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { cx, PTR_OFFSET_WITH_CAST, expr.span, - &msg, + msg, "try", sugg, Applicability::MachineApplicable, ); } else { - span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg); + span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg); } } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index b57220e6cf0..927c6f1d519 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,7 +4,7 @@ use clippy_config::msrvs::Msrv; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, @@ -14,7 +14,8 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, + BindingAnnotation, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, + Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; @@ -109,12 +110,31 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { + /// Make sure the init expr implements try trait so a valid suggestion could be given. + /// + /// Because the init expr could have the type of `&Option<T>` which does not implements `Try`. + /// + /// NB: This conveniently prevents the cause of + /// issue [#12412](https://github.com/rust-lang/rust-clippy/issues/12412), + /// since accessing an `Option` field from a borrowed struct requires borrow, such as + /// `&some_struct.opt`, which is type of `&Option`. And we can't suggest `&some_struct.opt?` + /// or `(&some_struct.opt)?` since the first one has different semantics and the later does + /// not implements `Try`. + fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -> bool { + let init_ty = cx.typeck_results().expr_ty_adjusted(init_expr); + cx.tcx + .lang_items() + .try_trait() + .map_or(false, |did| implements_trait(cx, init_ty, did, &[])) + } + if let StmtKind::Let(LetStmt { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind + && init_expr_can_use_question_mark(cx, init_expr) && let Some(ret) = find_let_else_ret_expression(els) && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret) && !span_contains_comment(cx.tcx.sess.source_map(), els.span) @@ -310,9 +330,9 @@ impl QuestionMark { } } -fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool { +fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool { if let Some(expr) = bl.expr - && let rustc_hir::ExprKind::Call(callee, _) = expr.kind + && let ExprKind::Call(callee, _) = expr.kind { is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput) } else { @@ -341,7 +361,7 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } } - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if is_try_block(cx, block) { *self .try_block_depth_stack @@ -350,15 +370,15 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } } - fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) { + fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { self.try_block_depth_stack.push(0); } - fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) { + fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { self.try_block_depth_stack.pop(); } - fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) { + fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if is_try_block(cx, block) { *self .try_block_depth_stack diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 6b54258dd61..186e548d373 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -242,7 +242,7 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `{range_type}::contains` implementation"), + format!("manual `{range_type}::contains` implementation"), "use", format!("({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, @@ -272,7 +272,7 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `!{range_type}::contains` implementation"), + format!("manual `!{range_type}::contains` implementation"), "use", format!("!({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 435899ddaa7..2863eb190d3 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -56,7 +56,7 @@ impl ReturnVisitor { impl<'tcx> Visitor<'tcx> for ReturnVisitor { fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind { + if let ExprKind::Ret(_) | ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind { self.found_return = true; } else { hir_visit::walk_expr(self, ex); @@ -68,7 +68,7 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor { /// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression /// }`. fn is_async_closure(body: &hir::Body<'_>) -> bool { - if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind + if let ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind // checks whether it is `async || whatever_expression` && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind @@ -99,7 +99,7 @@ fn find_innermost_closure<'tcx>( )> { let mut data = None; - while let hir::ExprKind::Closure(closure) = expr.kind + while let ExprKind::Closure(closure) = expr.kind && let body = cx.tcx.hir().body(closure.body) && { let mut visitor = ReturnVisitor::new(); @@ -137,7 +137,7 @@ fn get_parent_call_exprs<'tcx>( ) -> (&'tcx hir::Expr<'tcx>, usize) { let mut depth = 1; while let Some(parent) = get_parent_expr(cx, expr) - && let hir::ExprKind::Call(recv, _) = parent.kind + && let ExprKind::Call(recv, _) = parent.kind && expr.span == recv.span { expr = parent; @@ -152,13 +152,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { return; } - if let hir::ExprKind::Call(recv, _) = expr.kind + if let ExprKind::Call(recv, _) = expr.kind // don't lint if the receiver is a call, too. // we do this in order to prevent linting multiple times; consider: // `(|| || 1)()()` // ^^ we only want to lint for this call (but we walk up the calls to consider both calls). // without this check, we'd end up linting twice. - && !matches!(recv.kind, hir::ExprKind::Call(..)) + && !matches!(recv.kind, ExprKind::Call(..)) // Check if `recv` comes from a macro expansion. If it does, make sure that it's an expansion that is // the same as the one the call is in. // For instance, let's assume `x!()` returns a closure: @@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); if coroutine_kind.is_async() - && let hir::ExprKind::Closure(closure) = body.kind + && let ExprKind::Closure(closure) = body.kind { // Like `async fn`, async closures are wrapped in an additional block // to move all of the closure's arguments into the future. @@ -202,7 +202,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { }; // `async x` is a syntax error, so it becomes `async { x }` - if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) { + if !matches!(body_expr.kind, ExprKind::Block(_, _)) { hint = hint.blockify(); } @@ -210,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { } let is_in_fn_call_arg = if let Node::Expr(expr) = cx.tcx.parent_hir_node(expr.hir_id) { - matches!(expr.kind, hir::ExprKind::Call(_, _)) + matches!(expr.kind, ExprKind::Call(_, _)) } else { false }; @@ -238,12 +238,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { path: &'tcx hir::Path<'tcx>, count: usize, } - impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { + impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Call(closure, _) = expr.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind + if let ExprKind::Call(closure, _) = expr.kind + && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind && self.path.segments[0].ident == path.segments[0].ident && self.path.res == path.res { @@ -263,13 +263,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { for w in block.stmts.windows(2) { if let hir::StmtKind::Let(local) = w[0].kind - && let Option::Some(t) = local.init - && let hir::ExprKind::Closure { .. } = t.kind + && let Some(t) = local.init + && let ExprKind::Closure { .. } = t.kind && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind && let hir::StmtKind::Semi(second) = w[1].kind - && let hir::ExprKind::Assign(_, call, _) = second.kind - && let hir::ExprKind::Call(closure, _) = call.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind + && let ExprKind::Assign(_, call, _) = second.kind + && let ExprKind::Call(closure, _) = call.kind + && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind && ident == path.segments[0].ident && count_closure_usage(cx, block, path) == 1 { diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 0f579f779df..7202266deeb 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -77,9 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { cx, REDUNDANT_LOCALS, local.span, - &format!("redundant redefinition of a binding `{ident}`"), + format!("redundant redefinition of a binding `{ident}`"), Some(binding_pat.span), - &format!("`{ident}` is initially defined here"), + format!("`{ident}` is initially defined here"), ); } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 0e43e4a7ee5..1b557730eca 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { cx, REDUNDANT_PUB_CRATE, span, - &format!("pub(crate) {descr} inside private module"), + format!("pub(crate) {descr} inside private module"), |diag| { diag.span_suggestion( item.vis_span, diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 07b604f2326..136e7db83bd 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -48,7 +48,7 @@ impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); impl RedundantStaticLifetimes { // Recursively visit types - fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) { + fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &'static str) { match ty.kind { // Be careful of nested structures (arrays and tuples) TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => { diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 96f6f0ec36f..11b95ee3a54 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -59,7 +59,7 @@ fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, f fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::HirId) -> Option<Ty<'tcx>> { if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(hir_id) - && defkind == hir::def::DefKind::AssocFn + && defkind == DefKind::AssocFn && let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars() { Some(init_ty) diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 687bad35a36..e925ec0271c 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -134,13 +134,13 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape vec![convert_span(primary)] }; - span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}")); + span_lint(cx, INVALID_REGEX, spans, format!("regex syntax error: {kind}")); } else { span_lint_and_help( cx, INVALID_REGEX, base, - &error.to_string(), + error.to_string(), None, "consider using a raw string literal: `r\"..\"`", ); @@ -223,7 +223,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, - Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()), + Err(e) => span_lint(cx, INVALID_REGEX, expr.span, e.to_string()), } } } diff --git a/clippy_lints/src/repeat_vec_with_capacity.rs b/clippy_lints/src/repeat_vec_with_capacity.rs index fcb79f6d694..a358881bf80 100644 --- a/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/clippy_lints/src/repeat_vec_with_capacity.rs @@ -55,7 +55,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s cx, REPEAT_VEC_WITH_CAPACITY, span, - &format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), + format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), |diag| { diag.note(note); diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 8bc24eda465..e8f9d438104 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{ - fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, + fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; @@ -232,6 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { && !in_external_macro(cx.sess(), initexpr.span) && !in_external_macro(cx.sess(), retexpr.span) && !local.span.from_expansion() + && !span_contains_cfg(cx, stmt.span.between(retexpr.span)) { span_lint_hir_and_then( cx, diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 85a2b1a6735..23b47606f8a 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { cx, SELF_NAMED_CONSTRUCTORS, impl_item.span, - &format!("constructor `{}` has the same name as the type", impl_item.ident.name), + format!("constructor `{}` has the same name as the type", impl_item.ident.name), ); } } diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index b4278d879e5..f1ec91d7aff 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// Checks for misuses of the serde API. /// /// ### Why is this bad? - /// Serde is very finnicky about how its API should be + /// Serde is very finicky about how its API should be /// used, but the type system can't be used to enforce it (yet?). /// /// ### Example diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index d98b37bda35..9db08acb03b 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -194,7 +194,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) cx, lint, span, - &msg, + msg, Some(cx.tcx.hir().span(shadowed)), "previous binding is here", ); diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 95b4a11a783..0a9a3c6307a 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -122,7 +122,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { cx, SINGLE_RANGE_IN_VEC_INIT, span, - &format!("{suggested_type} of `Range` that is only one element"), + format!("{suggested_type} of `Range` that is only one element"), |diag| { if should_emit_every_value { diag.span_suggestion( diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index ff8e8fe7021..8a9f02b6dcb 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -196,7 +196,7 @@ impl SlowVectorInit { }; } - fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) { + fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &'static str) { let len_expr = Sugg::hir( cx, match vec_alloc.size_expr { diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index cf839941123..926c56332cc 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -128,8 +128,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { cx, lint, first_segment.ident.span, - &format!("used import from `{used_mod}` instead of `{replace_with}`"), - &format!("consider importing the item from `{replace_with}`"), + format!("used import from `{used_mod}` instead of `{replace_with}`"), + format!("consider importing the item from `{replace_with}`"), replace_with.to_string(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 13ae1ff52dd..b3c729dacdd 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -495,8 +495,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { cx, TRIM_SPLIT_WHITESPACE, trim_span.with_hi(split_ws_span.lo()), - &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), - &format!("remove `{trim_fn_name}()`"), + format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), + format!("remove `{trim_fn_name}()`"), String::new(), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 8eab3f5874e..3f030b80331 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { cx, lint, binop.span, - &format!( + format!( "suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id) diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index be590aede15..93bad865809 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,10 +1,16 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::{snippet_indent, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; + use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core}; +use itertools::Itertools; + +use rustc_hir::intravisit::{walk_expr, Visitor}; + +use crate::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; @@ -80,7 +86,17 @@ impl<'tcx> LateLintPass<'tcx> for Swap { } } -fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) { +#[allow(clippy::too_many_arguments)] +fn generate_swap_warning<'tcx>( + block: &'tcx Block<'tcx>, + cx: &LateContext<'tcx>, + e1: &'tcx Expr<'tcx>, + e2: &'tcx Expr<'tcx>, + rhs1: &'tcx Expr<'tcx>, + rhs2: &'tcx Expr<'tcx>, + span: Span, + is_xor_based: bool, +) { let ctxt = span.ctxt(); let mut applicability = Applicability::MachineApplicable; @@ -99,14 +115,25 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa || is_type_diagnostic_item(cx, ty, sym::VecDeque) { let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability); + span_lint_and_sugg( cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping elements of `{slice}` manually"), + format!("this looks like you are swapping elements of `{slice}` manually"), "try", format!( - "{}.swap({}, {});", + "{}{}.swap({}, {});", + IndexBinding { + block, + swap1_idx: idx1, + swap2_idx: idx2, + suggest_span: span, + cx, + ctxt, + applicability: &mut applicability, + } + .snippet_index_bindings(&[idx1, idx2, rhs1, rhs2]), slice.maybe_par(), snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0, snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0, @@ -126,7 +153,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping `{first}` and `{second}` manually"), + format!("this looks like you are swapping `{first}` and `{second}` manually"), |diag| { diag.span_suggestion( span, @@ -142,7 +169,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa } /// Implementation of the `MANUAL_SWAP` lint. -fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { +fn check_manual_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if in_constant(cx, block.hir_id) { return; } @@ -160,10 +187,10 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { // bar() = t; && let StmtKind::Semi(second) = s3.kind && let ExprKind::Assign(lhs2, rhs2, _) = second.kind - && let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind - && rhs2.segments.len() == 1 + && let ExprKind::Path(QPath::Resolved(None, rhs2_path)) = rhs2.kind + && rhs2_path.segments.len() == 1 - && ident.name == rhs2.segments[0].ident.name + && ident.name == rhs2_path.segments[0].ident.name && eq_expr_value(cx, tmp_init, lhs1) && eq_expr_value(cx, rhs1, lhs2) @@ -174,7 +201,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { && second.span.ctxt() == ctxt { let span = s1.span.to(s3.span); - generate_swap_warning(cx, lhs1, lhs2, span, false); + generate_swap_warning(block, cx, lhs1, lhs2, rhs1, rhs2, span, false); } } } @@ -201,7 +228,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { cx, ALMOST_SWAPPED, span, - &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), + format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), |diag| { diag.span_suggestion( span, @@ -254,7 +281,7 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< } /// Implementation of the xor case for `MANUAL_SWAP` lint. -fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { +fn check_xor_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { for [s1, s2, s3] in block.stmts.array_windows::<3>() { let ctxt = s1.span.ctxt(); if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt) @@ -268,7 +295,7 @@ fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { && s3.span.ctxt() == ctxt { let span = s1.span.to(s3.span); - generate_swap_warning(cx, lhs0, rhs0, span, true); + generate_swap_warning(block, cx, lhs0, rhs0, rhs1, rhs2, span, true); }; } } @@ -294,3 +321,130 @@ fn extract_sides_of_xor_assign<'a, 'hir>( None } } + +struct IndexBinding<'a, 'tcx> { + block: &'a Block<'a>, + swap1_idx: &'a Expr<'a>, + swap2_idx: &'a Expr<'a>, + suggest_span: Span, + cx: &'a LateContext<'tcx>, + ctxt: SyntaxContext, + applicability: &'a mut Applicability, +} + +impl<'a, 'tcx> IndexBinding<'a, 'tcx> { + fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String { + let mut bindings = FxHashSet::default(); + for expr in exprs { + bindings.insert(self.snippet_index_binding(expr)); + } + bindings.into_iter().join("") + } + + fn snippet_index_binding(&mut self, expr: &'tcx Expr<'tcx>) -> String { + match expr.kind { + ExprKind::Binary(_, lhs, rhs) => { + if matches!(lhs.kind, ExprKind::Lit(_)) && matches!(rhs.kind, ExprKind::Lit(_)) { + return String::new(); + } + let lhs_snippet = self.snippet_index_binding(lhs); + let rhs_snippet = self.snippet_index_binding(rhs); + format!("{lhs_snippet}{rhs_snippet}") + }, + ExprKind::Path(QPath::Resolved(_, path)) => { + let init = self.cx.expr_or_init(expr); + + let Some(first_segment) = path.segments.first() else { + return String::new(); + }; + if !self.suggest_span.contains(init.span) || !self.is_used_other_than_swapping(first_segment.ident) { + return String::new(); + } + + let init_str = snippet_with_context(self.cx, init.span, self.ctxt, "", self.applicability) + .0 + .to_string(); + let indent_str = snippet_indent(self.cx, init.span); + let indent_str = indent_str.as_deref().unwrap_or(""); + + format!("let {} = {init_str};\n{indent_str}", first_segment.ident) + }, + _ => String::new(), + } + } + + fn is_used_other_than_swapping(&mut self, idx_ident: Ident) -> bool { + if Self::is_used_slice_indexed(self.swap1_idx, idx_ident) + || Self::is_used_slice_indexed(self.swap2_idx, idx_ident) + { + return true; + } + self.is_used_after_swap(idx_ident) + } + + fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool { + let mut v = IndexBindingVisitor { + found_used: false, + suggest_span: self.suggest_span, + idx: idx_ident, + }; + + for stmt in self.block.stmts { + match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => v.visit_expr(expr), + StmtKind::Let(LetStmt { ref init, .. }) => { + if let Some(init) = init.as_ref() { + v.visit_expr(init); + } + }, + StmtKind::Item(_) => {}, + } + } + + v.found_used + } + + fn is_used_slice_indexed(swap_index: &Expr<'_>, idx_ident: Ident) -> bool { + match swap_index.kind { + ExprKind::Binary(_, lhs, rhs) => { + if matches!(lhs.kind, ExprKind::Lit(_)) && matches!(rhs.kind, ExprKind::Lit(_)) { + return false; + } + Self::is_used_slice_indexed(lhs, idx_ident) || Self::is_used_slice_indexed(rhs, idx_ident) + }, + ExprKind::Path(QPath::Resolved(_, path)) => { + path.segments.first().map_or(false, |idx| idx.ident == idx_ident) + }, + _ => false, + } + } +} + +struct IndexBindingVisitor { + idx: Ident, + suggest_span: Span, + found_used: bool, +} + +impl<'tcx> Visitor<'tcx> for IndexBindingVisitor { + fn visit_path_segment(&mut self, path_segment: &'tcx rustc_hir::PathSegment<'tcx>) -> Self::Result { + if path_segment.ident == self.idx { + self.found_used = true; + } + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + if expr.span.hi() <= self.suggest_span.hi() { + return; + } + + match expr.kind { + ExprKind::Path(QPath::Resolved(_, path)) => { + for segment in path.segments { + self.visit_path_segment(segment); + } + }, + _ => walk_expr(self, expr), + } + } +} diff --git a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs index f8bdb866ca3..c1e24674e3e 100644 --- a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs @@ -59,7 +59,7 @@ impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZE #[inline] fn is_thread_local_initializer( cx: &LateContext<'_>, - fn_kind: rustc_hir::intravisit::FnKind<'_>, + fn_kind: intravisit::FnKind<'_>, span: rustc_span::Span, ) -> Option<bool> { let macro_def_id = span.source_callee()?.macro_def_id?; @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { fn check_fn( &mut self, cx: &LateContext<'tcx>, - fn_kind: rustc_hir::intravisit::FnKind<'tcx>, + fn_kind: intravisit::FnKind<'tcx>, _: &'tcx rustc_hir::FnDecl<'tcx>, body: &'tcx rustc_hir::Body<'tcx>, span: rustc_span::Span, diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index cbdf31c9336..462084e96a8 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", None, - &format!( + format!( "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute", cx.tcx.def_path_str(item.owner_id) ), diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 768623b5d03..9468d367a92 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -293,7 +293,7 @@ impl TraitBounds { p.span, "this type has already been used as a bound predicate", None, - &hint_string, + hint_string, ); } } @@ -420,7 +420,11 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ) } -fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> { +fn rollup_traits( + cx: &LateContext<'_>, + bounds: &[GenericBound<'_>], + msg: &'static str, +) -> Vec<(ComparableTraitRef, Span)> { let mut map = FxHashMap::default(); let mut repeated_res = false; diff --git a/clippy_lints/src/transmute/crosspointer_transmute.rs b/clippy_lints/src/transmute/crosspointer_transmute.rs index 102aee1cb95..c8f959a9854 100644 --- a/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), + format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), ); true }, @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), + format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), ); true }, diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs new file mode 100644 index 00000000000..cc6ff1cf3b4 --- /dev/null +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -0,0 +1,87 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Ty; + +use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS; + +fn get_parent_local_binding_ty<'tcx>(cx: &LateContext<'tcx>, expr_hir_id: HirId) -> Option<LetStmt<'tcx>> { + let mut parent_iter = cx.tcx.hir().parent_iter(expr_hir_id); + if let Some((_, node)) = parent_iter.next() { + match node { + Node::LetStmt(local) => Some(*local), + Node::Block(_) => { + if let Some((parent_hir_id, Node::Expr(expr))) = parent_iter.next() + && matches!(expr.kind, rustc_hir::ExprKind::Block(_, _)) + { + get_parent_local_binding_ty(cx, parent_hir_id) + } else { + None + } + }, + _ => None, + } + } else { + None + } +} + +fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool { + let def_id = cx.tcx.hir().enclosing_body_owner(expr_hir_id); + if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id) { + let body = cx.tcx.hir().body(body_id); + return body.value.peel_blocks().hir_id == expr_hir_id; + } + false +} + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + path: &Path<'tcx>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, + expr_hir_id: HirId, +) -> bool { + let last = path.segments.last().unwrap(); + if in_external_macro(cx.tcx.sess, last.ident.span) { + // If it comes from a non-local macro, we ignore it. + return false; + } + let args = last.args; + let missing_generic = match args { + Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| match arg { + GenericArg::Infer(_) => true, + GenericArg::Type(ty) => matches!(ty.kind, TyKind::Infer), + _ => false, + }), + _ => true, + }; + if !missing_generic { + return false; + } + // If it's being set as a local variable value... + if let Some(local) = get_parent_local_binding_ty(cx, expr_hir_id) { + // ... which does have type annotations. + if let Some(ty) = local.ty + // If this is a `let x: _ =`, we should lint. + && !matches!(ty.kind, TyKind::Infer) + { + return false; + } + // We check if this transmute is not the only element in the function + } else if is_function_block(cx, expr_hir_id) { + return false; + } + span_lint_and_sugg( + cx, + MISSING_TRANSMUTE_ANNOTATIONS, + last.ident.span.with_hi(path.span.hi()), + "transmute used without annotations", + "consider adding missing annotations", + format!("{}::<{from_ty}, {to_ty}>", last.ident.as_str()), + Applicability::MaybeIncorrect, + ); + true +} diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 3c11b481310..7fa536a1a29 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -1,5 +1,6 @@ mod crosspointer_transmute; mod eager_transmute; +mod missing_transmute_annotations; mod transmute_float_to_int; mod transmute_int_to_bool; mod transmute_int_to_char; @@ -520,6 +521,37 @@ declare_clippy_lint! { "eager evaluation of `transmute`" } +declare_clippy_lint! { + /// ### What it does + /// Checks if transmute calls have all generics specified. + /// + /// ### Why is this bad? + /// If not set, some unexpected output type could be retrieved instead of the expected one, + /// potentially leading to invalid code. + /// + /// This is particularly dangerous in case a seemingly innocent/unrelated change can cause type + /// inference to start inferring a different type. E.g. the transmute is the tail expression of + /// an `if` branch, and a different branches type changes, causing the transmute to silently + /// have a different type, instead of a proper error. + /// + /// ### Example + /// ```no_run + /// # unsafe { + /// let x: i32 = std::mem::transmute([1u16, 2u16]); + /// # } + /// ``` + /// Use instead: + /// ```no_run + /// # unsafe { + /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + /// # } + /// ``` + #[clippy::version = "1.77.0"] + pub MISSING_TRANSMUTE_ANNOTATIONS, + suspicious, + "warns if a transmute call doesn't have all generics specified" +} + pub struct Transmute { msrv: Msrv, } @@ -542,6 +574,7 @@ impl_lint_pass!(Transmute => [ TRANSMUTING_NULL, TRANSMUTE_NULL_TO_FN, EAGER_TRANSMUTE, + MISSING_TRANSMUTE_ANNOTATIONS, ]); impl Transmute { #[must_use] @@ -579,6 +612,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmuting_null::check(cx, e, arg, to_ty) | transmute_null_to_fn::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) + | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) diff --git a/clippy_lints/src/transmute/transmute_float_to_int.rs b/clippy_lints/src/transmute/transmute_float_to_int.rs index aef520923e4..ab3bb5e1062 100644 --- a/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_FLOAT_TO_INT, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let mut sugg = sugg::Sugg::hir(cx, arg, ".."); diff --git a/clippy_lints/src/transmute/transmute_int_to_bool.rs b/clippy_lints/src/transmute/transmute_int_to_bool.rs index 58227c53de2..a7192809077 100644 --- a/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_BOOL, e.span, - &format!("transmute from a `{from_ty}` to a `bool`"), + format!("transmute from a `{from_ty}` to a `bool`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let zero = sugg::Sugg::NonParen(Cow::from("0")); diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 2a6c2481254..81d10a7d5bd 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_CHAR, e.span, - &format!("transmute from a `{from_ty}` to a `char`"), + format!("transmute from a `{from_ty}` to a `char`"), |diag| { let Some(top_crate) = std_or_core(cx) else { return }; let arg = sugg::Sugg::hir(cx, arg, ".."); diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index cc3422edbbf..d51888e3097 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_FLOAT, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(int_ty) = from_ty.kind() { diff --git a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 97068efd43c..234021f0f47 100644 --- a/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_NON_ZERO, e.span, - &format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), + format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 009d5a7c8ae..88b0ac5a368 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_NUM_TO_BYTES, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index cf78709583c..eaf927c0005 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_PTR_TO_REF, e.span, - &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), + format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = if *mutbl == Mutability::Mut { diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 73321c56f3f..3842c4eb60e 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_BYTES_TO_STR, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 33c4031fa87..9c8dd37d53d 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -71,7 +71,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{from_ty_orig}` which has an undefined layout"), + format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { diag.note(format!("the contained type `{from_ty}` has an undefined layout")); @@ -85,7 +85,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute to `{to_ty_orig}` which has an undefined layout"), + format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { diag.note(format!("the contained type `{to_ty}` has an undefined layout")); @@ -111,7 +111,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!( + format!( "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout" ), |diag| { @@ -140,7 +140,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{from_ty_orig}` which has an undefined layout"), + format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { diag.note(format!("the contained type `{from_ty}` has an undefined layout")); @@ -157,7 +157,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute into `{to_ty_orig}` which has an undefined layout"), + format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { diag.note(format!("the contained type `{to_ty}` has an undefined layout")); diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 043c9c88601..6f5ac625e35 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -53,7 +53,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), + format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), "try", sugg, app, diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 891fefc17a6..35e93830766 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, UNSOUND_COLLECTION_TRANSMUTE, e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), + format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), ); true } else { diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 70628f3d4f4..ec5fb2793f9 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( cx, USELESS_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to itself"), + format!("transmute from a type (`{from_ty}`) to itself"), ); true }, diff --git a/clippy_lints/src/transmute/wrong_transmute.rs b/clippy_lints/src/transmute/wrong_transmute.rs index ed815884a76..14a5a308a64 100644 --- a/clippy_lints/src/transmute/wrong_transmute.rs +++ b/clippy_lints/src/transmute/wrong_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, WRONG_TRANSMUTE, e.span, - &format!("transmute from a `{from_ty}` to a pointer"), + format!("transmute from a `{from_ty}` to a pointer"), ); true }, diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index fc3420af020..9ac73394548 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -21,9 +21,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, BOX_COLLECTION, hir_ty.span, - &format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), + format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), None, - &format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), + format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), ); true } else { diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 37437cbfbec..0801eace4fc 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{generic_snippet}>`"), + format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); diag.note(format!( @@ -73,7 +73,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), + format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.span_suggestion( hir_ty.span, @@ -92,7 +92,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), + format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs index 8764e3006c6..0c4e2c91aec 100644 --- a/clippy_lints/src/unconditional_recursion.rs +++ b/clippy_lints/src/unconditional_recursion.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// implementations. /// /// ### Why is this bad? - /// This is a hard to find infinite recursion that will crash any code. + /// This is a hard to find infinite recursion that will crash any code /// using it. /// /// ### Example diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 5fe4b74b3a7..cbd16180077 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -200,7 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { let item_has_safety_comment = item_has_safety_comment(cx, item); match (&item.kind, item_has_safety_comment) { // lint unsafe impl without safety comment - (hir::ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => { + (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => { if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) && !is_unsafe_from_proc_macro(cx, item.span) { @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } }, // lint safe impl with unnecessary safety comment - (hir::ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => { + (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => { if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { let (span, help_span) = mk_spans(pos); @@ -236,9 +236,9 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { ); } }, - (hir::ItemKind::Impl(_), _) => {}, + (ItemKind::Impl(_), _) => {}, // const and static items only need a safety comment if their body is an unsafe block, lint otherwise - (&hir::ItemKind::Const(.., body) | &hir::ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { + (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { let body = cx.tcx.hir().body(body); if !matches!( @@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { cx, UNNECESSARY_SAFETY_COMMENT, span, - &format!("{} has unnecessary safety comment", item.kind.descr()), + format!("{} has unnecessary safety comment", item.kind.descr()), Some(help_span), "consider removing the safety comment", ); @@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { cx, UNNECESSARY_SAFETY_COMMENT, span, - &format!("{} has unnecessary safety comment", item.kind.descr()), + format!("{} has unnecessary safety comment", item.kind.descr()), Some(help_span), "consider removing the safety comment", ); @@ -338,13 +338,13 @@ fn block_parents_have_safety_comment( accept_comment_above_statement: bool, accept_comment_above_attributes: bool, cx: &LateContext<'_>, - id: hir::HirId, + id: HirId, ) -> bool { let (span, hir_id) = match cx.tcx.parent_hir_node(id) { Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) { Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { - kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), span, owner_id, .. @@ -365,7 +365,7 @@ fn block_parents_have_safety_comment( }) | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { - kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), span, owner_id, .. @@ -605,11 +605,11 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> { Node::Expr(e) => span = e.span, Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::LetStmt(_) => (), Node::Item(hir::Item { - kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), .. }) => maybe_global_var = true, Node::Item(hir::Item { - kind: hir::ItemKind::Mod(_), + kind: ItemKind::Mod(_), span: item_span, .. }) => { diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 729972de6e6..214b69dc925 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { cx, UNIT_RETURN_EXPECTING_ORD, span, - &format!( + format!( "this closure returns \ the unit type which also implements {trait_name}" ), @@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { cx, UNIT_RETURN_EXPECTING_ORD, span, - &format!( + format!( "this closure returns \ the unit type which also implements {trait_name}" ), diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index ffb909d7907..80b661a757c 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_context; -use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; +use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, is_local_used}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::intravisit::{walk_body, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::{in_external_macro, is_from_async_await}; @@ -75,12 +76,53 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app); } + + if let PatKind::Binding(_, binding_hir_id, ident, ..) = local.pat.kind + && let Some(body_id) = cx.enclosing_body.as_ref() + && let body = cx.tcx.hir().body(*body_id) + && is_local_used(cx, body, binding_hir_id) + { + let identifier = ident.as_str(); + let mut visitor = UnitVariableCollector::new(binding_hir_id); + walk_body(&mut visitor, body); + visitor.spans.into_iter().for_each(|span| { + let msg = + format!("variable `{identifier}` of type `()` can be replaced with explicit `()`"); + diag.span_suggestion(span, msg, "()", Applicability::MachineApplicable); + }); + } }, ); } } } +struct UnitVariableCollector { + id: HirId, + spans: Vec<rustc_span::Span>, +} + +impl UnitVariableCollector { + fn new(id: HirId) -> Self { + Self { id, spans: vec![] } + } +} + +/** + * Collect all instances where a variable is used based on its `HirId`. + */ +impl<'tcx> Visitor<'tcx> for UnitVariableCollector { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Path(QPath::Resolved(None, path)) = ex.kind + && let Res::Local(id) = path.res + && id == self.id + { + self.spans.push(path.span); + } + rustc_hir::intravisit::walk_expr(self, ex); + } +} + /// Checks sub-expressions which create the value returned by the given expression for whether /// return value inference is needed. This checks through locals to see if they also need inference /// at this point. diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index eba7fa7b993..afc53e6f32d 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; use super::{utils, UNIT_ARG}; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if is_questionmark_desugar_marked_call(expr) { return; } - if let hir::Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) + if let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) && is_questionmark_desugar_marked_call(parent_expr) { return; @@ -69,7 +69,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp cx, UNIT_ARG, expr.span, - &format!("passing {singular}unit value{plural} to a function"), + format!("passing {singular}unit value{plural} to a function"), |db| { let mut or = ""; args_to_recover diff --git a/clippy_lints/src/unit_types/unit_cmp.rs b/clippy_lints/src/unit_types/unit_cmp.rs index d4342ec5169..6dcc1195a70 100644 --- a/clippy_lints/src/unit_types/unit_cmp.rs +++ b/clippy_lints/src/unit_types/unit_cmp.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, macro_call.span, - &format!("`{macro_name}` of unit values detected. This will always {result}"), + format!("`{macro_name}` of unit values detected. This will always {result}"), ); } return; @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, expr.span, - &format!( + format!( "{}-comparison of unit values detected. This will always be {result}", op.as_str() ), diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index c332cf076ae..bfcefb26153 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -88,7 +88,7 @@ impl UnnecessaryBoxReturns { cx, UNNECESSARY_BOX_RETURNS, return_ty_hir.span, - format!("boxed return of the sized type `{boxed_ty}`").as_str(), + format!("boxed return of the sized type `{boxed_ty}`"), |diagnostic| { diagnostic.span_suggestion( return_ty_hir.span, diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 2b0d2d61d20..8f1eb5019f0 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { hir::QPath::LangItem(..) => return, }; match constructor_symbol { - sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (), + sym::Some | sym::Ok if path.ident.name == sym::map => (), sym::Err if path.ident.name == sym::map_err => (), _ => return, } @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { cx, UNNECESSARY_MAP_ON_CONSTRUCTOR, expr.span, - &format!( + format!( "unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name ), diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 9c8b0ae1727..5c7fbbab988 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) }; - span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg.as_str(), |diag| { + span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| { diag.span_suggestion( fn_decl.output.span(), return_type_sugg_msg, diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index d4dd31e1178..0049de931f4 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -215,7 +215,7 @@ macro_rules! always_pat { /// in `alternatives[focus_idx + 1..]`. fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: usize) -> bool { // Extract the kind; we'll need to make some changes in it. - let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild); + let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, Wild); // We'll focus on `alternatives[focus_idx]`, // so we're draining from `alternatives[focus_idx + 1..]`. let start = focus_idx + 1; @@ -232,7 +232,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us // In the case of only two patterns, replacement adds net characters. | Ref(_, Mutability::Not) // Dealt with elsewhere. - | Or(_) | Paren(_) => false, + | Or(_) | Paren(_) | Deref(_) => false, // Transform `box x | ... | box y` into `box (x | y)`. // // The cases below until `Slice(...)` deal with *singleton* products. @@ -242,8 +242,6 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us |k| matches!(k, Box(_)), |k| always_pat!(k, Box(p) => p), ), - // FIXME(deref_patterns): Should we merge patterns here? - Deref(_) => false, // Transform `&mut x | ... | &mut y` into `&mut (x | y)`. Ref(target, Mutability::Mut) => extend_with_matching( target, start, alternatives, diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 3f2f765f751..51b3ea93b6d 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -65,7 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, cx, UNSAFE_REMOVED_FROM_NAME, span, - &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), + format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), ); } } diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index d8c5f1b7382..448946bd66d 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { if let Some(exp) = block.expr && matches!( exp.kind, - hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, hir::MatchSource::Normal) + ExprKind::If(_, _, _) | ExprKind::Match(_, _, hir::MatchSource::Normal) ) { check_expr(cx, exp); @@ -130,7 +130,7 @@ fn non_consuming_ok_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool { fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { match expr.kind { - hir::ExprKind::If(cond, _, _) + ExprKind::If(cond, _, _) if let ExprKind::Let(hir::LetExpr { pat, init, .. }) = cond.kind && is_ok_wild_or_dotdot_pattern(cx, pat) && let Some(op) = should_lint(cx, init) => @@ -140,7 +140,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { // we will capture only the case where the match is Ok( ) or Err( ) // prefer to match the minimum possible, and expand later if needed // to avoid false positives on something as used as this - hir::ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { + ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { if non_consuming_ok_arm(cx, arm1) && non_consuming_err_arm(cx, arm2) { emit_lint(cx, expr.span, expr.hir_id, op, &[arm1.pat.span]); } @@ -148,7 +148,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { emit_lint(cx, expr.span, expr.hir_id, op, &[arm2.pat.span]); } }, - hir::ExprKind::Match(_, _, hir::MatchSource::Normal) => {}, + ExprKind::Match(_, _, hir::MatchSource::Normal) => {}, _ if let Some(op) = should_lint(cx, expr) => { emit_lint(cx, expr.span, expr.hir_id, op, &[]); }, @@ -201,7 +201,7 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { } fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - while let hir::ExprKind::MethodCall(path, receiver, ..) = expr.kind { + while let ExprKind::MethodCall(path, receiver, ..) = expr.kind { if matches!( path.ident.as_str(), "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or" @@ -215,10 +215,10 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { } fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - while let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind + while let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind && matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) + ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) ) { expr = arg_0; @@ -227,7 +227,7 @@ fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { } fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - while let hir::ExprKind::Match(res, _, _) = expr.kind { + while let ExprKind::Match(res, _, _) = expr.kind { expr = res; } expr @@ -236,11 +236,11 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { - if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { - if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { + if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { + if let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { if matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) + ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) ) { return arg_0; } @@ -251,7 +251,7 @@ fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { /// Check whether the current expr is a function call for an IO operation fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option<IoOp> { - let hir::ExprKind::MethodCall(path, ..) = call.kind else { + let ExprKind::MethodCall(path, ..) = call.kind else { return None; }; diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index d5ca844b9e2..3e5afec541c 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -55,8 +55,8 @@ impl EarlyLintPass for UnusedRounding { cx, UNUSED_ROUNDING, expr.span, - &format!("used the `{method_name}` method with a whole number float"), - &format!("remove the `{method_name}` method call"), + format!("used the `{method_name}` method with a whole number float"), + format!("remove the `{method_name}` method call"), float, Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index f2eb774b5cb..2622abd59cb 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -338,7 +338,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { UNNECESSARY_UNWRAP, expr.hir_id, expr.span, - &format!( + format!( "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", method_name.ident.name, unwrappable.check_name.ident.as_str(), @@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { PANICKING_UNWRAP, expr.hir_id, expr.span, - &format!("this call to `{}()` will always panic", method_name.ident.name), + format!("this call to `{}()` will always panic", method_name.ident.name), |diag| { diag.span_label(unwrappable.check.span, "because of this check"); }, diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index a615ef11691..aca500590ce 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -59,7 +59,7 @@ declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind + if let ImplItemKind::Fn(ref _signature, _) = impl_item.kind // first check if it's a method or function // checking if its return type is `result` or `option` && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result) diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index d2a1d42f279..f376d349646 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -94,7 +94,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive UPPER_CASE_ACRONYMS, hir_id, span, - &format!("name `{ident}` contains a capitalized acronym"), + format!("name `{ident}` contains a capitalized acronym"), |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index a6b411d6c0f..0bab917607d 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } - fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) { + fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx>) { if !hir_ty.span.from_expansion() && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { @@ -286,7 +286,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector { walk_inf(self, inf); } - fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, hir_ty: &Ty<'_>) { self.types_to_skip.push(hir_ty.hir_id); walk_ty(self, hir_ty); diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index f7a455977fa..75541766156 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", sugg.into_owned(), app, @@ -301,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), None, "consider removing `.try_into()`", ); @@ -346,9 +346,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), None, - &hint, + hint, ); } @@ -360,8 +360,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), - &sugg_msg, + format!("useless conversion to the same type: `{b}`"), + sugg_msg, sugg.to_string(), app, ); diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index e45beb4910b..7b43abeef67 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -754,7 +754,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } } -fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { +fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir().attrs(hir_id); get_attr(cx.sess(), attrs, "author").count() > 0 } @@ -771,7 +771,7 @@ fn path_to_string(path: &QPath<'_>) -> Result<String, ()> { } }, QPath::TypeRelative(ty, segment) => match &ty.kind { - hir::TyKind::Path(inner_path) => { + TyKind::Path(inner_path) => { inner(s, inner_path)?; *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 4822970e47e..5483e80f932 100644 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { ident.span, "non-standard lint formulation", None, - &format!("consider using `{}`", formulation.correction), + format!("consider using `{}`", formulation.correction), ); } return; diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index 7c70d3f45db..f7529682675 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq}; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -72,7 +71,7 @@ declare_clippy_lint! { declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) { return; } diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index df37619227c..9b6b6871818 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { path.ident.span, "usage of a compiler lint function", None, - &format!("please use the Clippy variant of this function: `{sugg}`"), + format!("please use the Clippy variant of this function: `{sugg}`"), ); } } diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 370ed430bcf..9be225759df 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, DEFAULT_LINT, item.span, - &format!("the lint `{}` has the default lint description", item.ident.name), + format!("the lint `{}` has the default lint description", item.ident.name), ); } @@ -191,7 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, DEFAULT_DEPRECATION_REASON, item.span, - &format!("the lint `{}` has the default deprecation reason", item.ident.name), + format!("the lint `{}` has the default deprecation reason", item.ident.name), ); } } @@ -247,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, LINT_WITHOUT_LINT_PASS, lint_span, - &format!("the lint `{lint_name}` is not added to any `LintPass`"), + format!("the lint `{lint_name}` is not added to any `LintPass`"), ); } } diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c56c8ddc7a9..5c1ebb922f1 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -153,7 +153,7 @@ impl MetadataCollector { lints: BinaryHeap::<LintMetadata>::default(), applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), config: get_configuration_metadata(), - clippy_project_root: std::env::current_dir() + clippy_project_root: env::current_dir() .expect("failed to get current dir") .ancestors() .nth(1) @@ -243,7 +243,7 @@ Please use that command to update the file and do not edit it by hand. .unwrap(); // Write configuration links to CHANGELOG.md - let changelog = std::fs::read_to_string(CHANGELOG_PATH).unwrap(); + let changelog = fs::read_to_string(CHANGELOG_PATH).unwrap(); let mut changelog_file = File::create(CHANGELOG_PATH).unwrap(); let position = changelog .find("<!-- begin autogenerated links to configuration documentation -->") @@ -822,7 +822,7 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s cx, METADATA_COLLECTOR, item.ident.span, - &format!("metadata collection error for `{}`: {message}", item.ident.name), + format!("metadata collection error for `{}`: {message}", item.ident.name), ); } @@ -912,7 +912,7 @@ impl<'a, 'hir> LintResolver<'a, 'hir> { } } -impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for LintResolver<'a, 'hir> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { @@ -963,7 +963,7 @@ impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> { } } -impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { @@ -994,7 +994,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { } /// This returns the parent local node if the expression is a reference one -fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> { +fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::LetStmt<'hir>> { if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { if let hir::def::Res::Local(local_hir) = path.res { return get_parent_local_hir_id(cx, local_hir); @@ -1004,7 +1004,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) - None } -fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { +fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::LetStmt<'hir>> { match cx.tcx.parent_hir_node(hir_id) { hir::Node::LetStmt(local) => Some(local), hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id), @@ -1042,7 +1042,7 @@ impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> { } } -impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 8d208fbb7e9..63fcbd61528 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -51,8 +51,8 @@ impl LateLintPass<'_> for MsrvAttrImpl { cx, MISSING_MSRV_ATTR_IMPL, span, - &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), - &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), + format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), + format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")), Applicability::MachineApplicable, ); diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 304a1379374..8cf42832761 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -4,10 +4,9 @@ use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_ use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind, Local, Mutability, Node}; +use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; @@ -49,7 +48,7 @@ pub struct UnnecessaryDefPath { } impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { return; } @@ -79,9 +78,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { cx, UNNECESSARY_DEF_PATH, span, - &format!("hardcoded path to a {msg}"), + format!("hardcoded path to a {msg}"), None, - &format!("convert all references to use `{sugg}`"), + format!("convert all references to use `{sugg}`"), ); } } @@ -213,11 +212,11 @@ impl UnnecessaryDefPath { } } -fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<String>> { +fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Vec<String>> { match peel_hir_expr_refs(expr).0.kind { ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { - if let Node::LetStmt(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { + if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { path_to_matched_type(cx, init) } else { None diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 83369c66367..9818b98dd5b 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -89,7 +89,7 @@ impl EarlyLintPass for Visibility { cx, NEEDLESS_PUB_SELF, item.vis.span, - &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), + format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), "remove it", String::new(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index be16d2e5cc3..26c6859233d 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -297,11 +297,11 @@ impl<'tcx> LateLintPass<'tcx> for Write { match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { - span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`")); + span_lint(cx, PRINT_STDOUT, macro_call.span, format!("use of `{name}!`")); } }, sym::eprint_macro | sym::eprintln_macro if !allowed_in_tests => { - span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`")); + span_lint(cx, PRINT_STDERR, macro_call.span, format!("use of `{name}!`")); }, sym::write_macro | sym::writeln_macro => {}, _ => return, @@ -390,7 +390,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma cx, lint, macro_call.span, - &format!("using `{name}!()` with a format string that ends in a single newline"), + format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); let Some(format_snippet) = snippet_opt(cx, format_string_span) else { @@ -440,7 +440,7 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call cx, lint, macro_call.span, - &format!("empty string literal in `{name}!`"), + format!("empty string literal in `{name}!`"), |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index d3623d6fda4..662242f6196 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { expr.span, "constant division of `0.0` with `0.0` will always result in NaN", None, - &format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), + format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), ); } } |
