about summary refs log tree commit diff
path: root/clippy_utils/src
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-06-13 12:18:48 +0200
committerPhilipp Krones <hello@philkrones.com>2024-06-13 12:24:08 +0200
commitcc63143bbf5ae28daae127902090492560313ca1 (patch)
tree3cf8901da2767e0e330b32ef8a1f8a3bf75adc0c /clippy_utils/src
parent35f54fd439432f56c749fbb34f1326e34ed1fc42 (diff)
parentaaade2d12d3cf78fd9eb24bf7973e86433d6373d (diff)
Merge remote-tracking branch 'upstream/master' into rustup
Diffstat (limited to 'clippy_utils/src')
-rw-r--r--clippy_utils/src/consts.rs14
-rw-r--r--clippy_utils/src/hir_utils.rs12
-rw-r--r--clippy_utils/src/lib.rs24
-rw-r--r--clippy_utils/src/macros.rs10
-rw-r--r--clippy_utils/src/ptr.rs4
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs10
-rw-r--r--clippy_utils/src/source.rs47
-rw-r--r--clippy_utils/src/ty.rs43
-rw-r--r--clippy_utils/src/ty/type_certainty/mod.rs14
-rw-r--r--clippy_utils/src/usage.rs8
-rw-r--r--clippy_utils/src/visitors.rs14
11 files changed, 158 insertions, 42 deletions
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index e9e1aa7e445..cfd142fe1ff 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -412,7 +412,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     /// Simple constant folding: Insert an expression, get a constant or none.
     pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
+            ExprKind::DropTemps(e) => self.expr(e),
             ExprKind::Path(ref qpath) => {
                 self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
                     let result = mir_to_const(this.lcx, result)?;
@@ -490,7 +491,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     /// leaves the local crate.
     pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
         match e.kind {
-            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr_is_empty(e),
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
+            ExprKind::DropTemps(e) => self.expr_is_empty(e),
             ExprKind::Path(ref qpath) => {
                 if !self
                     .typeck_results
@@ -811,12 +813,8 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
             ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
             ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))),
-            ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
-                int.try_into().expect("invalid f32 bit representation"),
-            ))),
-            ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
-                int.try_into().expect("invalid f64 bit representation"),
-            ))),
+            ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))),
+            ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))),
             ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))),
             _ => None,
         },
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index 36634817fc9..50dd8430ac0 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::MatchSource::TryDesugar;
 use rustc_hir::{
-    ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
-    GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
-    PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, AssocItemConstraint,
+    ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy,
+    GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField,
+    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
@@ -519,7 +519,11 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_ty(left.ty().expect("expected assoc type binding"), right.ty().expect("expected assoc type binding"))
+        left.ident.name == right.ident.name
+            && self.eq_ty(
+                left.ty().expect("expected assoc type binding"),
+                right.ty().expect("expected assoc type binding"),
+            )
     }
 
     fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 2f6bf920967..7dc341ec8d7 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -126,7 +126,7 @@ use visitors::Visitable;
 use crate::consts::{constant, mir_to_const, Constant};
 use crate::higher::Range;
 use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
-use crate::visitors::for_each_expr;
+use crate::visitors::for_each_expr_without_closures;
 
 use rustc_middle::hir::nested_filter;
 
@@ -321,6 +321,15 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
         .map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 }
 
+/// Checks if the given method call expression calls an inherent method.
+pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+        cx.tcx.trait_of_item(method_id).is_none()
+    } else {
+        false
+    }
+}
+
 /// Checks if a method is defined in an impl of a diagnostic item
 pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
     if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
@@ -1313,7 +1322,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<
 
 /// Returns `true` if `expr` contains a return expression
 pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
-    for_each_expr(expr, |e| {
+    for_each_expr_without_closures(expr, |e| {
         if matches!(e.kind, ExprKind::Ret(..)) {
             ControlFlow::Break(())
         } else {
@@ -3392,3 +3401,14 @@ pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool {
 
     contains_block(expr, false)
 }
+
+/// Returns true if the specified expression is in a receiver position.
+pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(parent_expr) = get_parent_expr(cx, expr)
+        && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind
+        && receiver.hir_id == expr.hir_id
+    {
+        return true;
+    }
+    false
+}
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index 8daab9b0d92..455239cc37f 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::similar_names)] // `expr` and `expn`
 
-use crate::visitors::{for_each_expr, Descend};
+use crate::visitors::{for_each_expr_without_closures, Descend};
 
 use arrayvec::ArrayVec;
 use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
@@ -323,7 +323,7 @@ fn find_assert_args_inner<'a, const N: usize>(
         Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?,
     };
     let mut args = ArrayVec::new();
-    let panic_expn = for_each_expr(expr, |e| {
+    let panic_expn = for_each_expr_without_closures(expr, |e| {
         if args.is_full() {
             match PanicExpn::parse(e) {
                 Some(expn) => ControlFlow::Break(expn),
@@ -349,7 +349,7 @@ fn find_assert_within_debug_assert<'a>(
     expn: ExpnId,
     assert_name: Symbol,
 ) -> Option<(&'a Expr<'a>, ExpnId)> {
-    for_each_expr(expr, |e| {
+    for_each_expr_without_closures(expr, |e| {
         if !e.span.from_expansion() {
             return ControlFlow::Continue(Descend::No);
         }
@@ -397,7 +397,7 @@ impl FormatArgsStorage {
     ///
     /// See also [`find_format_arg_expr`]
     pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> {
-        let format_args_expr = for_each_expr(start, |expr| {
+        let format_args_expr = for_each_expr_without_closures(start, |expr| {
             let ctxt = expr.span.ctxt();
             if ctxt.outer_expn().is_descendant_of(expn_id) {
                 if macro_backtrace(expr.span)
@@ -439,7 +439,7 @@ pub fn find_format_arg_expr<'hir, 'ast>(
         parent: _,
     } = target.expr.span.data();
 
-    for_each_expr(start, |expr| {
+    for_each_expr_without_closures(start, |expr| {
         // When incremental compilation is enabled spans gain a parent during AST to HIR lowering,
         // since we're comparing an AST span to a HIR one we need to ignore the parent field
         let data = expr.span.data();
diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs
index 88837d8a143..991ea428dc3 100644
--- a/clippy_utils/src/ptr.rs
+++ b/clippy_utils/src/ptr.rs
@@ -1,5 +1,5 @@
 use crate::source::snippet;
-use crate::visitors::{for_each_expr, Descend};
+use crate::visitors::{for_each_expr_without_closures, Descend};
 use crate::{path_to_local_id, strip_pat_refs};
 use core::ops::ControlFlow;
 use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
@@ -31,7 +31,7 @@ fn extract_clone_suggestions<'tcx>(
     body: &'tcx Body<'_>,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     let mut spans = Vec::new();
-    for_each_expr(body, |e| {
+    for_each_expr_without_closures(body, |e| {
         if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
             && path_to_local_id(recv, id)
         {
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 81e94725a70..42b10f69c0c 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -40,9 +40,13 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
     )?;
 
     for bb in &*body.basic_blocks {
-        check_terminator(tcx, body, bb.terminator(), msrv)?;
-        for stmt in &bb.statements {
-            check_statement(tcx, body, def_id, stmt, msrv)?;
+        // Cleanup blocks are ignored entirely by const eval, so we can too:
+        // https://github.com/rust-lang/rust/blob/1dea922ea6e74f99a0e97de5cdb8174e4dea0444/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382
+        if !bb.is_cleanup {
+            check_terminator(tcx, body, bb.terminator(), msrv)?;
+            for stmt in &bb.statements {
+                check_statement(tcx, body, def_id, stmt, msrv)?;
+            }
         }
     }
     Ok(())
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index fd67e039c29..b7ff7ebe910 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -2,13 +2,14 @@
 
 #![allow(clippy::module_name_repetitions)]
 
+use rustc_ast::{LitKind, StrStyle};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
 use rustc_lint::{LateContext, LintContext};
 use rustc_session::Session;
 use rustc_span::source_map::{original_sp, SourceMap};
-use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
+use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP};
 use std::borrow::Cow;
 use std::ops::Range;
 
@@ -500,6 +501,50 @@ pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
     extended.with_lo(extended.lo() - BytePos(1))
 }
 
+/// Converts `expr` to a `char` literal if it's a `str` literal containing a single
+/// character (or a single byte with `ascii_only`)
+pub fn str_literal_to_char_literal(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    applicability: &mut Applicability,
+    ascii_only: bool,
+) -> Option<String> {
+    if let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Str(r, style) = lit.node
+        && let string = r.as_str()
+        && let len = if ascii_only {
+            string.len()
+        } else {
+            string.chars().count()
+        }
+        && len == 1
+    {
+        let snip = snippet_with_applicability(cx, expr.span, string, applicability);
+        let ch = if let StrStyle::Raw(nhash) = style {
+            let nhash = nhash as usize;
+            // for raw string: r##"a"##
+            &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
+        } else {
+            // for regular string: "a"
+            &snip[1..(snip.len() - 1)]
+        };
+
+        let hint = format!(
+            "'{}'",
+            match ch {
+                "'" => "\\'",
+                r"\" => "\\\\",
+                "\\\"" => "\"", // no need to escape `"` in `'"'`
+                _ => ch,
+            }
+        );
+
+        Some(hint)
+    } else {
+        None
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::{reindent_multiline, without_block_comments};
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 6e5626297c9..7d4332a3d9d 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -17,9 +17,9 @@ use rustc_middle::mir::ConstValue;
 use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
+    GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@@ -861,7 +861,6 @@ impl core::ops::Add<u32> for EnumValue {
 }
 
 /// Attempts to read the given constant as though it were an enum value.
-#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
 pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
     if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
         match tcx.type_of(id).instantiate_identity().kind() {
@@ -1314,3 +1313,39 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>
 pub fn is_manually_drop(ty: Ty<'_>) -> bool {
     ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop)
 }
+
+/// Returns the deref chain of a type, starting with the type itself.
+pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
+    iter::successors(Some(ty), |&ty| {
+        if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
+            && implements_trait(cx, ty, deref_did, &[])
+        {
+            make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
+        } else {
+            None
+        }
+    })
+}
+
+/// Checks if a Ty<'_> has some inherent method Symbol.
+/// This does not look for impls in the type's `Deref::Target` type.
+/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
+pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
+    if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
+        cx.tcx
+            .inherent_impls(ty_did)
+            .into_iter()
+            .flatten()
+            .map(|&did| {
+                cx.tcx
+                    .associated_items(did)
+                    .filter_by_name_unhygienic(method_name)
+                    .next()
+                    .filter(|item| item.kind == AssocKind::Fn)
+            })
+            .next()
+            .flatten()
+    } else {
+        None
+    }
+}
diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs
index 80219303450..cba61c841ef 100644
--- a/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/clippy_utils/src/ty/type_certainty/mod.rs
@@ -206,8 +206,18 @@ fn path_segment_certainty(
             // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
             if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
                 let generics = cx.tcx.generics_of(def_id);
-                let count = generics.own_params.len() - usize::from(generics.host_effect_index.is_some());
-                let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 {
+
+                let own_count = generics.own_params.len()
+                    - usize::from(generics.host_effect_index.is_some_and(|index| {
+                        // Check that the host index actually belongs to this resolution.
+                        // E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add`
+                        // trait's generics.
+                        // Add params:      [Self#0, Rhs#1, host#2]   parent_count=0, count=3
+                        // Add::add params: []                        parent_count=3, count=3
+                        // (3..3).contains(&host_effect_index) => false
+                        (generics.parent_count..generics.count()).contains(&index)
+                    }));
+                let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 {
                     Certainty::Certain(None)
                 } else {
                     Certainty::Uncertain
diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs
index 2a25d51d8e5..fbf3d95365a 100644
--- a/clippy_utils/src/usage.rs
+++ b/clippy_utils/src/usage.rs
@@ -1,4 +1,4 @@
-use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable};
+use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable};
 use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
 use core::ops::ControlFlow;
 use hir::def::Res;
@@ -145,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
 }
 
 pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
-    for_each_expr(expression, |e| {
+    for_each_expr_without_closures(expression, |e| {
         match e.kind {
             ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()),
             // Something special could be done here to handle while or for loop
@@ -159,7 +159,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
 }
 
 pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
-    for_each_expr_with_closures(cx, v, |e| {
+    for_each_expr(cx, v, |e| {
         if utils::path_to_local_id(e, local_id) {
             ControlFlow::Break(())
         } else {
@@ -184,7 +184,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
     let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
 
     let mut past_expr = false;
-    for_each_expr_with_closures(cx, block, |e| {
+    for_each_expr(cx, block, |e| {
         if past_expr {
             if utils::path_to_local_id(e, local_id) {
                 ControlFlow::Break(())
diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs
index 90b56297bb5..3a39e178515 100644
--- a/clippy_utils/src/visitors.rs
+++ b/clippy_utils/src/visitors.rs
@@ -100,7 +100,7 @@ visitable_ref!(Stmt, visit_stmt);
 
 /// Calls the given function once for each expression contained. This does not enter any bodies or
 /// nested items.
-pub fn for_each_expr<'tcx, B, C: Continue>(
+pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
 ) -> Option<B> {
@@ -134,7 +134,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
 
 /// Calls the given function once for each expression contained. This will enter bodies, but not
 /// nested items.
-pub fn for_each_expr_with_closures<'tcx, B, C: Continue>(
+pub fn for_each_expr<'tcx, B, C: Continue>(
     cx: &LateContext<'tcx>,
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
@@ -181,7 +181,7 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>(
 
 /// returns `true` if expr contains match expr desugared from try
 fn contains_try(expr: &Expr<'_>) -> bool {
-    for_each_expr(expr, |e| {
+    for_each_expr_without_closures(expr, |e| {
         if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) {
             ControlFlow::Break(())
         } else {
@@ -286,7 +286,7 @@ where
 
 /// Checks if the given resolved path is used in the given body.
 pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
-    for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| {
+    for_each_expr(cx, cx.tcx.hir().body(body).value, |e| {
         if let ExprKind::Path(p) = &e.kind {
             if cx.qpath_res(p, e.hir_id) == res {
                 return ControlFlow::Break(());
@@ -299,7 +299,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
 
 /// Checks if the given local is used.
 pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
-    for_each_expr_with_closures(cx, visitable, |e| {
+    for_each_expr(cx, visitable, |e| {
         if path_to_local_id(e, id) {
             ControlFlow::Break(())
         } else {
@@ -757,7 +757,7 @@ pub fn for_each_local_assignment<'tcx, B>(
 }
 
 pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
-    for_each_expr(expr, |e| {
+    for_each_expr_without_closures(expr, |e| {
         if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) {
             ControlFlow::Break(())
         } else {
@@ -776,7 +776,7 @@ pub fn local_used_once<'tcx>(
 ) -> Option<&'tcx Expr<'tcx>> {
     let mut expr = None;
 
-    let cf = for_each_expr_with_closures(cx, visitable, |e| {
+    let cf = for_each_expr(cx, visitable, |e| {
         if path_to_local_id(e, id) && expr.replace(e).is_some() {
             ControlFlow::Break(())
         } else {