clippy_utils/
lib.rs

1#![feature(box_patterns)]
2#![feature(if_let_guard)]
3#![feature(macro_metavar_expr)]
4#![feature(never_type)]
5#![feature(rustc_private)]
6#![feature(assert_matches)]
7#![feature(unwrap_infallible)]
8#![feature(array_windows)]
9#![recursion_limit = "512"]
10#![allow(
11    clippy::missing_errors_doc,
12    clippy::missing_panics_doc,
13    clippy::must_use_candidate,
14    rustc::diagnostic_outside_of_impl,
15    rustc::untranslatable_diagnostic
16)]
17#![warn(
18    trivial_casts,
19    trivial_numeric_casts,
20    rust_2018_idioms,
21    unused_lifetimes,
22    unused_qualifications,
23    rustc::internal
24)]
25
26// FIXME: switch to something more ergonomic here, once available.
27// (Currently there is no way to opt into sysroot crates without `extern crate`.)
28extern crate rustc_abi;
29extern crate rustc_ast;
30extern crate rustc_attr_parsing;
31extern crate rustc_const_eval;
32extern crate rustc_data_structures;
33#[expect(
34    unused_extern_crates,
35    reason = "The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate."
36)]
37extern crate rustc_driver;
38extern crate rustc_errors;
39extern crate rustc_hir;
40extern crate rustc_hir_analysis;
41extern crate rustc_hir_typeck;
42extern crate rustc_index;
43extern crate rustc_infer;
44extern crate rustc_lexer;
45extern crate rustc_lint;
46extern crate rustc_middle;
47extern crate rustc_mir_dataflow;
48extern crate rustc_session;
49extern crate rustc_span;
50extern crate rustc_trait_selection;
51
52pub mod ast_utils;
53pub mod attrs;
54mod check_proc_macro;
55pub mod comparisons;
56pub mod consts;
57pub mod diagnostics;
58pub mod eager_or_lazy;
59pub mod higher;
60mod hir_utils;
61pub mod macros;
62pub mod mir;
63pub mod msrvs;
64pub mod numeric_literal;
65pub mod paths;
66pub mod qualify_min_const_fn;
67pub mod res;
68pub mod source;
69pub mod str_utils;
70pub mod sugg;
71pub mod sym;
72pub mod ty;
73pub mod usage;
74pub mod visitors;
75
76pub use self::attrs::*;
77pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
78pub use self::hir_utils::{
79    HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, has_ambiguous_literal_in_expr, hash_expr,
80    hash_stmt, is_bool, over,
81};
82
83use core::mem;
84use core::ops::ControlFlow;
85use std::collections::hash_map::Entry;
86use std::iter::{once, repeat_n, zip};
87use std::sync::{Mutex, MutexGuard, OnceLock};
88
89use itertools::Itertools;
90use rustc_abi::Integer;
91use rustc_ast::ast::{self, LitKind, RangeLimits};
92use rustc_ast::join_path_syms;
93use rustc_data_structures::fx::FxHashMap;
94use rustc_data_structures::indexmap;
95use rustc_data_structures::packed::Pu128;
96use rustc_data_structures::unhash::UnindexMap;
97use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
98use rustc_hir::attrs::AttributeKind;
99use rustc_hir::def::{DefKind, Res};
100use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
101use rustc_hir::definitions::{DefPath, DefPathData};
102use rustc_hir::hir_id::{HirIdMap, HirIdSet};
103use rustc_hir::intravisit::{Visitor, walk_expr};
104use rustc_hir::{
105    self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring,
106    CoroutineKind, CoroutineSource, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs,
107    HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId,
108    OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
109    TraitItemKind, TraitRef, TyKind, UnOp, def, find_attr,
110};
111use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
112use rustc_lint::{LateContext, Level, Lint, LintContext};
113use rustc_middle::hir::nested_filter;
114use rustc_middle::hir::place::PlaceBase;
115use rustc_middle::lint::LevelAndSource;
116use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};
117use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, PointerCoercion};
118use rustc_middle::ty::layout::IntegerExt;
119use rustc_middle::ty::{
120    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt,
121    TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
122};
123use rustc_span::hygiene::{ExpnKind, MacroKind};
124use rustc_span::source_map::SourceMap;
125use rustc_span::symbol::{Ident, Symbol, kw};
126use rustc_span::{InnerSpan, Span};
127use source::{SpanRangeExt, walk_span_to_context};
128use visitors::{Visitable, for_each_unconsumed_temporary};
129
130use crate::ast_utils::unordered_over;
131use crate::consts::{ConstEvalCtxt, Constant};
132use crate::higher::Range;
133use crate::msrvs::Msrv;
134use crate::res::{MaybeDef, MaybeResPath};
135use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
136use crate::visitors::for_each_expr_without_closures;
137
138#[macro_export]
139macro_rules! extract_msrv_attr {
140    () => {
141        fn check_attributes(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::ast::Attribute]) {
142            let sess = rustc_lint::LintContext::sess(cx);
143            self.msrv.check_attributes(sess, attrs);
144        }
145
146        fn check_attributes_post(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::ast::Attribute]) {
147            let sess = rustc_lint::LintContext::sess(cx);
148            self.msrv.check_attributes_post(sess, attrs);
149        }
150    };
151}
152
153/// If the given expression is a local binding, find the initializer expression.
154/// If that initializer expression is another local binding, find its initializer again.
155///
156/// This process repeats as long as possible (but usually no more than once). Initializer
157/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
158/// instead.
159///
160/// Examples:
161/// ```no_run
162/// let abc = 1;
163/// //        ^ output
164/// let def = abc;
165/// dbg!(def);
166/// //   ^^^ input
167///
168/// // or...
169/// let abc = 1;
170/// let def = abc + 2;
171/// //        ^^^^^^^ output
172/// dbg!(def);
173/// //   ^^^ input
174/// ```
175pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
176    while let Some(init) = expr
177        .res_local_id()
178        .and_then(|id| find_binding_init(cx, id))
179        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
180    {
181        expr = init;
182    }
183    expr
184}
185
186/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
187///
188/// By only considering immutable bindings, we guarantee that the returned expression represents the
189/// value of the binding wherever it is referenced.
190///
191/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
192/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
193/// canonical binding `HirId`.
194pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
195    if let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
196        && matches!(pat.kind, PatKind::Binding(BindingMode::NONE, ..))
197        && let Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id)
198    {
199        return local.init;
200    }
201    None
202}
203
204/// Checks if the given local has an initializer or is from something other than a `let` statement
205///
206/// e.g. returns true for `x` in `fn f(x: usize) { .. }` and `let x = 1;` but false for `let x;`
207pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
208    for (_, node) in cx.tcx.hir_parent_iter(local) {
209        match node {
210            Node::Pat(..) | Node::PatField(..) => {},
211            Node::LetStmt(let_stmt) => return let_stmt.init.is_some(),
212            _ => return true,
213        }
214    }
215
216    false
217}
218
219/// Checks if we are currently in a const context (e.g. `const fn`, `static`/`const` initializer).
220///
221/// The current context is determined based on the current body which is set before calling a lint's
222/// entry point (any function on `LateLintPass`). If you need to check in a different context use
223/// `tcx.hir_is_inside_const_context(_)`.
224///
225/// Do not call this unless the `LateContext` has an enclosing body. For release build this case
226/// will safely return `false`, but debug builds will ICE. Note that `check_expr`, `check_block`,
227/// `check_pat` and a few other entry points will always have an enclosing body. Some entry points
228/// like `check_path` or `check_ty` may or may not have one.
229pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
230    debug_assert!(cx.enclosing_body.is_some(), "`LateContext` has no enclosing body");
231    cx.enclosing_body.is_some_and(|id| {
232        cx.tcx
233            .hir_body_const_context(cx.tcx.hir_body_owner_def_id(id))
234            .is_some()
235    })
236}
237
238/// Returns `true` if the given `HirId` is inside an always constant context.
239///
240/// This context includes:
241///  * const/static items
242///  * const blocks (or inline consts)
243///  * associated constants
244pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
245    use rustc_hir::ConstContext::{Const, ConstFn, Static};
246    let Some(ctx) = tcx.hir_body_const_context(tcx.hir_enclosing_body_owner(hir_id)) else {
247        return false;
248    };
249    match ctx {
250        ConstFn => false,
251        Static(_) | Const { inline: _ } => true,
252    }
253}
254
255/// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`.
256pub fn is_enum_variant_ctor(
257    cx: &LateContext<'_>,
258    enum_item: Symbol,
259    variant_name: Symbol,
260    ctor_call_id: DefId,
261) -> bool {
262    let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else {
263        return false;
264    };
265
266    let variants = cx.tcx.adt_def(enum_def_id).variants().iter();
267    variants
268        .filter(|variant| variant.name == variant_name)
269        .filter_map(|variant| variant.ctor.as_ref())
270        .any(|(_, ctor_def_id)| *ctor_def_id == ctor_call_id)
271}
272
273/// Checks if the `DefId` matches the given diagnostic item or it's constructor.
274pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool {
275    let did = match cx.tcx.def_kind(did) {
276        DefKind::Ctor(..) => cx.tcx.parent(did),
277        // Constructors for types in external crates seem to have `DefKind::Variant`
278        DefKind::Variant => match cx.tcx.opt_parent(did) {
279            Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
280            _ => did,
281        },
282        _ => did,
283    };
284
285    cx.tcx.is_diagnostic_item(item, did)
286}
287
288/// Checks if the `DefId` matches the given `LangItem` or it's constructor.
289pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool {
290    let did = match cx.tcx.def_kind(did) {
291        DefKind::Ctor(..) => cx.tcx.parent(did),
292        // Constructors for types in external crates seem to have `DefKind::Variant`
293        DefKind::Variant => match cx.tcx.opt_parent(did) {
294            Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
295            _ => did,
296        },
297        _ => did,
298    };
299
300    cx.tcx.lang_items().get(item) == Some(did)
301}
302
303/// Checks if `expr` is an empty block or an empty tuple.
304pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
305    matches!(
306        expr.kind,
307        ExprKind::Block(
308            Block {
309                stmts: [],
310                expr: None,
311                ..
312            },
313            _
314        ) | ExprKind::Tup([])
315    )
316}
317
318/// Checks if given pattern is a wildcard (`_`)
319pub fn is_wild(pat: &Pat<'_>) -> bool {
320    matches!(pat.kind, PatKind::Wild)
321}
322
323/// Checks if the `pat` is `None`.
324pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
325    matches!(pat.kind,
326        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
327            if cx.qpath_res(qpath, pat.hir_id).ctor_parent(cx).is_lang_item(cx, OptionNone))
328}
329
330/// Checks if `arm` has the form `None => None`.
331pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
332    is_none_pattern(cx, arm.pat)
333        && matches!(
334            peel_blocks(arm.body).kind,
335            ExprKind::Path(qpath)
336            if cx.qpath_res(&qpath, arm.body.hir_id).ctor_parent(cx).is_lang_item(cx, OptionNone)
337        )
338}
339
340/// Checks if the given `QPath` belongs to a type alias.
341pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
342    match *qpath {
343        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
344        QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath),
345        _ => false,
346    }
347}
348
349/// Checks if the `def_id` belongs to a function that is part of a trait impl.
350pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
351    if let Node::Item(item) = cx.tcx.parent_hir_node(cx.tcx.local_def_id_to_hir_id(def_id))
352        && let ItemKind::Impl(imp) = item.kind
353    {
354        imp.of_trait.is_some()
355    } else {
356        false
357    }
358}
359
360pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
361    match *path {
362        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
363        QPath::TypeRelative(_, seg) => seg,
364        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
365    }
366}
367
368pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
369    last_path_segment(qpath)
370        .args
371        .map_or(&[][..], |a| a.args)
372        .iter()
373        .filter_map(|a| match a {
374            GenericArg::Type(ty) => Some(ty.as_unambig_ty()),
375            _ => None,
376        })
377}
378
379/// If the expression is a path to a local (with optional projections),
380/// returns the canonical `HirId` of the local.
381///
382/// For example, `x.field[0].field2` would return the `HirId` of `x`.
383pub fn path_to_local_with_projections(expr: &Expr<'_>) -> Option<HirId> {
384    match expr.kind {
385        ExprKind::Field(recv, _) | ExprKind::Index(recv, _, _) => path_to_local_with_projections(recv),
386        ExprKind::Path(QPath::Resolved(
387            _,
388            Path {
389                res: Res::Local(local), ..
390            },
391        )) => Some(*local),
392        _ => None,
393    }
394}
395
396/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
397///
398/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
399///
400/// ```no_run
401/// struct Point(isize, isize);
402///
403/// impl std::ops::Add for Point {
404///     type Output = Self;
405///
406///     fn add(self, other: Self) -> Self {
407///         Point(0, 0)
408///     }
409/// }
410/// ```
411pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
412    if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
413        && let ItemKind::Impl(impl_) = &item.kind
414        && let Some(of_trait) = impl_.of_trait
415    {
416        return Some(&of_trait.trait_ref);
417    }
418    None
419}
420
421/// This method will return tuple of projection stack and root of the expression,
422/// used in `can_mut_borrow_both`.
423///
424/// For example, if `e` represents the `v[0].a.b[x]`
425/// this method will return a tuple, composed of a `Vec`
426/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
427/// and an `Expr` for root of them, `v`
428fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
429    let mut result = vec![];
430    let root = loop {
431        match e.kind {
432            ExprKind::Index(ep, _, _) | ExprKind::Field(ep, _) => {
433                result.push(e);
434                e = ep;
435            },
436            _ => break e,
437        }
438    };
439    result.reverse();
440    (result, root)
441}
442
443/// Gets the mutability of the custom deref adjustment, if any.
444pub fn expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability> {
445    cx.typeck_results()
446        .expr_adjustments(e)
447        .iter()
448        .find_map(|a| match a.kind {
449            Adjust::Deref(Some(d)) => Some(Some(d.mutbl)),
450            Adjust::Deref(None) => None,
451            _ => Some(None),
452        })
453        .and_then(|x| x)
454}
455
456/// Checks if two expressions can be mutably borrowed simultaneously
457/// and they aren't dependent on borrowing same thing twice
458pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
459    let (s1, r1) = projection_stack(e1);
460    let (s2, r2) = projection_stack(e2);
461    if !eq_expr_value(cx, r1, r2) {
462        return true;
463    }
464    if expr_custom_deref_adjustment(cx, r1).is_some() || expr_custom_deref_adjustment(cx, r2).is_some() {
465        return false;
466    }
467
468    for (x1, x2) in zip(&s1, &s2) {
469        if expr_custom_deref_adjustment(cx, x1).is_some() || expr_custom_deref_adjustment(cx, x2).is_some() {
470            return false;
471        }
472
473        match (&x1.kind, &x2.kind) {
474            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
475                if i1 != i2 {
476                    return true;
477                }
478            },
479            (ExprKind::Index(_, i1, _), ExprKind::Index(_, i2, _)) => {
480                if !eq_expr_value(cx, i1, i2) {
481                    return false;
482                }
483            },
484            _ => return false,
485        }
486    }
487    false
488}
489
490/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
491/// constructor from the std library
492fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
493    let std_types_symbols = &[
494        sym::Vec,
495        sym::VecDeque,
496        sym::LinkedList,
497        sym::HashMap,
498        sym::BTreeMap,
499        sym::HashSet,
500        sym::BTreeSet,
501        sym::BinaryHeap,
502    ];
503
504    if let QPath::TypeRelative(_, method) = path
505        && method.ident.name == sym::new
506        && let Some(impl_did) = cx.tcx.impl_of_assoc(def_id)
507        && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
508    {
509        return Some(adt.did()) == cx.tcx.lang_items().string()
510            || (cx.tcx.get_diagnostic_name(adt.did())).is_some_and(|adt_name| std_types_symbols.contains(&adt_name));
511    }
512    false
513}
514
515/// Returns true if the expr is equal to `Default::default` when evaluated.
516pub fn is_default_equivalent_call(
517    cx: &LateContext<'_>,
518    repl_func: &Expr<'_>,
519    whole_call_expr: Option<&Expr<'_>>,
520) -> bool {
521    if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind
522        && let Some(repl_def) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def(cx)
523        && (repl_def.assoc_fn_parent(cx).is_diag_item(cx, sym::Default)
524            || is_default_equivalent_ctor(cx, repl_def.1, repl_func_qpath))
525    {
526        return true;
527    }
528
529    // Get the type of the whole method call expression, find the exact method definition, look at
530    // its body and check if it is similar to the corresponding `Default::default()` body.
531    let Some(e) = whole_call_expr else { return false };
532    let Some(default_fn_def_id) = cx.tcx.get_diagnostic_item(sym::default_fn) else {
533        return false;
534    };
535    let Some(ty) = cx.tcx.typeck(e.hir_id.owner.def_id).expr_ty_adjusted_opt(e) else {
536        return false;
537    };
538    let args = rustc_ty::GenericArgs::for_item(cx.tcx, default_fn_def_id, |param, _| {
539        if let rustc_ty::GenericParamDefKind::Lifetime = param.kind {
540            cx.tcx.lifetimes.re_erased.into()
541        } else if param.index == 0 && param.name == kw::SelfUpper {
542            ty.into()
543        } else {
544            param.to_error(cx.tcx)
545        }
546    });
547    let instance = rustc_ty::Instance::try_resolve(cx.tcx, cx.typing_env(), default_fn_def_id, args);
548
549    let Ok(Some(instance)) = instance else { return false };
550    if let rustc_ty::InstanceKind::Item(def) = instance.def
551        && !cx.tcx.is_mir_available(def)
552    {
553        return false;
554    }
555    let ExprKind::Path(ref repl_func_qpath) = repl_func.kind else {
556        return false;
557    };
558    let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() else {
559        return false;
560    };
561
562    // Get the MIR Body for the `<Ty as Default>::default()` function.
563    // If it is a value or call (either fn or ctor), we compare its `DefId` against the one for the
564    // resolution of the expression we had in the path. This lets us identify, for example, that
565    // the body of `<Vec<T> as Default>::default()` is a `Vec::new()`, and the field was being
566    // initialized to `Vec::new()` as well.
567    let body = cx.tcx.instance_mir(instance.def);
568    for block_data in body.basic_blocks.iter() {
569        if block_data.statements.len() == 1
570            && let StatementKind::Assign(assign) = &block_data.statements[0].kind
571            && assign.0.local == RETURN_PLACE
572            && let Rvalue::Aggregate(kind, _places) = &assign.1
573            && let AggregateKind::Adt(did, variant_index, _, _, _) = &**kind
574            && let def = cx.tcx.adt_def(did)
575            && let variant = &def.variant(*variant_index)
576            && variant.fields.is_empty()
577            && let Some((_, did)) = variant.ctor
578            && did == repl_def_id
579        {
580            return true;
581        } else if block_data.statements.is_empty()
582            && let Some(term) = &block_data.terminator
583        {
584            match &term.kind {
585                TerminatorKind::Call {
586                    func: Operand::Constant(c),
587                    ..
588                } if let rustc_ty::FnDef(did, _args) = c.ty().kind()
589                    && *did == repl_def_id =>
590                {
591                    return true;
592                },
593                TerminatorKind::TailCall {
594                    func: Operand::Constant(c),
595                    ..
596                } if let rustc_ty::FnDef(did, _args) = c.ty().kind()
597                    && *did == repl_def_id =>
598                {
599                    return true;
600                },
601                _ => {},
602            }
603        }
604    }
605    false
606}
607
608/// Returns true if the expr is equal to `Default::default()` of its type when evaluated.
609///
610/// It doesn't cover all cases, like struct literals, but it is a close approximation.
611pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
612    match &e.kind {
613        ExprKind::Lit(lit) => match lit.node {
614            LitKind::Bool(false) | LitKind::Int(Pu128(0), _) => true,
615            LitKind::Str(s, _) => s.is_empty(),
616            _ => false,
617        },
618        ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
619        ExprKind::Repeat(x, len) => {
620            if let ConstArgKind::Anon(anon_const) = len.kind
621                && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind
622                && let LitKind::Int(v, _) = const_lit.node
623                && v <= 32
624                && is_default_equivalent(cx, x)
625            {
626                true
627            } else {
628                false
629            }
630        },
631        ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func, Some(e)),
632        ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg),
633        ExprKind::Path(qpath) => cx
634            .qpath_res(qpath, e.hir_id)
635            .ctor_parent(cx)
636            .is_lang_item(cx, OptionNone),
637        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
638        ExprKind::Block(Block { stmts: [], expr, .. }, _) => expr.is_some_and(|e| is_default_equivalent(cx, e)),
639        _ => false,
640    }
641}
642
643fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {
644    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind
645        && seg.ident.name == sym::from
646    {
647        match arg.kind {
648            ExprKind::Lit(hir::Lit {
649                node: LitKind::Str(sym, _),
650                ..
651            }) => return sym.is_empty() && ty.basic_res().is_lang_item(cx, LangItem::String),
652            ExprKind::Array([]) => return ty.basic_res().is_diag_item(cx, sym::Vec),
653            ExprKind::Repeat(_, len) => {
654                if let ConstArgKind::Anon(anon_const) = len.kind
655                    && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind
656                    && let LitKind::Int(v, _) = const_lit.node
657                {
658                    return v == 0 && ty.basic_res().is_diag_item(cx, sym::Vec);
659                }
660            },
661            _ => (),
662        }
663    }
664    false
665}
666
667/// Checks if the top level expression can be moved into a closure as is.
668/// Currently checks for:
669/// * Break/Continue outside the given loop HIR ids.
670/// * Yield/Return statements.
671/// * Inline assembly.
672/// * Usages of a field of a local where the type of the local can be partially moved.
673///
674/// For example, given the following function:
675///
676/// ```no_run
677/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
678///     for item in iter {
679///         let s = item.1;
680///         if item.0 > 10 {
681///             continue;
682///         } else {
683///             s.clear();
684///         }
685///     }
686/// }
687/// ```
688///
689/// When called on the expression `item.0` this will return false unless the local `item` is in the
690/// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it
691/// isn't always safe to move into a closure when only a single field is needed.
692///
693/// When called on the `continue` expression this will return false unless the outer loop expression
694/// is in the `loop_ids` set.
695///
696/// Note that this check is not recursive, so passing the `if` expression will always return true
697/// even though sub-expressions might return false.
698pub fn can_move_expr_to_closure_no_visit<'tcx>(
699    cx: &LateContext<'tcx>,
700    expr: &'tcx Expr<'_>,
701    loop_ids: &[HirId],
702    ignore_locals: &HirIdSet,
703) -> bool {
704    match expr.kind {
705        ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
706        | ExprKind::Continue(Destination { target_id: Ok(id), .. })
707            if loop_ids.contains(&id) =>
708        {
709            true
710        },
711        ExprKind::Break(..)
712        | ExprKind::Continue(_)
713        | ExprKind::Ret(_)
714        | ExprKind::Yield(..)
715        | ExprKind::InlineAsm(_) => false,
716        // Accessing a field of a local value can only be done if the type isn't
717        // partially moved.
718        ExprKind::Field(
719            &Expr {
720                hir_id,
721                kind:
722                    ExprKind::Path(QPath::Resolved(
723                        _,
724                        Path {
725                            res: Res::Local(local_id),
726                            ..
727                        },
728                    )),
729                ..
730            },
731            _,
732        ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {
733            // TODO: check if the local has been partially moved. Assume it has for now.
734            false
735        },
736        _ => true,
737    }
738}
739
740/// How a local is captured by a closure
741#[derive(Debug, Clone, Copy, PartialEq, Eq)]
742pub enum CaptureKind {
743    Value,
744    Use,
745    Ref(Mutability),
746}
747impl CaptureKind {
748    pub fn is_imm_ref(self) -> bool {
749        self == Self::Ref(Mutability::Not)
750    }
751}
752impl std::ops::BitOr for CaptureKind {
753    type Output = Self;
754    fn bitor(self, rhs: Self) -> Self::Output {
755        match (self, rhs) {
756            (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
757            (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use,
758            (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
759            | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
760            (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
761        }
762    }
763}
764impl std::ops::BitOrAssign for CaptureKind {
765    fn bitor_assign(&mut self, rhs: Self) {
766        *self = *self | rhs;
767    }
768}
769
770/// Given an expression referencing a local, determines how it would be captured in a closure.
771///
772/// Note as this will walk up to parent expressions until the capture can be determined it should
773/// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
774/// function argument (other than a receiver).
775pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
776    fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
777        let mut capture = CaptureKind::Ref(Mutability::Not);
778        pat.each_binding_or_first(&mut |_, id, span, _| match cx
779            .typeck_results()
780            .extract_binding_mode(cx.sess(), id, span)
781            .0
782        {
783            ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => {
784                capture = CaptureKind::Value;
785            },
786            ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => {
787                capture = CaptureKind::Ref(Mutability::Mut);
788            },
789            _ => (),
790        });
791        capture
792    }
793
794    debug_assert!(matches!(
795        e.kind,
796        ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))
797    ));
798
799    let mut child_id = e.hir_id;
800    let mut capture = CaptureKind::Value;
801    let mut capture_expr_ty = e;
802
803    for (parent_id, parent) in cx.tcx.hir_parent_iter(e.hir_id) {
804        if let [
805            Adjustment {
806                kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
807                target,
808            },
809            ref adjust @ ..,
810        ] = *cx
811            .typeck_results()
812            .adjustments()
813            .get(child_id)
814            .map_or(&[][..], |x| &**x)
815            && let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) =
816                *adjust.last().map_or(target, |a| a.target).kind()
817        {
818            return CaptureKind::Ref(mutability);
819        }
820
821        match parent {
822            Node::Expr(e) => match e.kind {
823                ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),
824                ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),
825                ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {
826                    return CaptureKind::Ref(Mutability::Mut);
827                },
828                ExprKind::Field(..) => {
829                    if capture == CaptureKind::Value {
830                        capture_expr_ty = e;
831                    }
832                },
833                ExprKind::Let(let_expr) => {
834                    let mutability = match pat_capture_kind(cx, let_expr.pat) {
835                        CaptureKind::Value | CaptureKind::Use => Mutability::Not,
836                        CaptureKind::Ref(m) => m,
837                    };
838                    return CaptureKind::Ref(mutability);
839                },
840                ExprKind::Match(_, arms, _) => {
841                    let mut mutability = Mutability::Not;
842                    for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
843                        match capture {
844                            CaptureKind::Value | CaptureKind::Use => break,
845                            CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
846                            CaptureKind::Ref(Mutability::Not) => (),
847                        }
848                    }
849                    return CaptureKind::Ref(mutability);
850                },
851                _ => break,
852            },
853            Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) {
854                CaptureKind::Value | CaptureKind::Use => break,
855                capture @ CaptureKind::Ref(_) => return capture,
856            },
857            _ => break,
858        }
859
860        child_id = parent_id;
861    }
862
863    if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {
864        // Copy types are never automatically captured by value.
865        CaptureKind::Ref(Mutability::Not)
866    } else {
867        capture
868    }
869}
870
871/// Checks if the expression can be moved into a closure as is. This will return a list of captures
872/// if so, otherwise, `None`.
873pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
874    struct V<'cx, 'tcx> {
875        cx: &'cx LateContext<'tcx>,
876        // Stack of potential break targets contained in the expression.
877        loops: Vec<HirId>,
878        /// Local variables created in the expression. These don't need to be captured.
879        locals: HirIdSet,
880        /// Whether this expression can be turned into a closure.
881        allow_closure: bool,
882        /// Locals which need to be captured, and whether they need to be by value, reference, or
883        /// mutable reference.
884        captures: HirIdMap<CaptureKind>,
885    }
886    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
887        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
888            if !self.allow_closure {
889                return;
890            }
891
892            match e.kind {
893                ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {
894                    if !self.locals.contains(&l) {
895                        let cap = capture_local_usage(self.cx, e);
896                        self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
897                    }
898                },
899                ExprKind::Closure(closure) => {
900                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) {
901                        let local_id = match capture.place.base {
902                            PlaceBase::Local(id) => id,
903                            PlaceBase::Upvar(var) => var.var_path.hir_id,
904                            _ => continue,
905                        };
906                        if !self.locals.contains(&local_id) {
907                            let capture = match capture.info.capture_kind {
908                                UpvarCapture::ByValue => CaptureKind::Value,
909                                UpvarCapture::ByUse => CaptureKind::Use,
910                                UpvarCapture::ByRef(kind) => match kind {
911                                    BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not),
912                                    BorrowKind::UniqueImmutable | BorrowKind::Mutable => {
913                                        CaptureKind::Ref(Mutability::Mut)
914                                    },
915                                },
916                            };
917                            self.captures
918                                .entry(local_id)
919                                .and_modify(|e| *e |= capture)
920                                .or_insert(capture);
921                        }
922                    }
923                },
924                ExprKind::Loop(b, ..) => {
925                    self.loops.push(e.hir_id);
926                    self.visit_block(b);
927                    self.loops.pop();
928                },
929                _ => {
930                    self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);
931                    walk_expr(self, e);
932                },
933            }
934        }
935
936        fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
937            p.each_binding_or_first(&mut |_, id, _, _| {
938                self.locals.insert(id);
939            });
940        }
941    }
942
943    let mut v = V {
944        cx,
945        loops: Vec::new(),
946        locals: HirIdSet::default(),
947        allow_closure: true,
948        captures: HirIdMap::default(),
949    };
950    v.visit_expr(expr);
951    v.allow_closure.then_some(v.captures)
952}
953
954/// Arguments of a method: the receiver and all the additional arguments.
955pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;
956
957/// Returns the method names and argument list of nested method call expressions that make up
958/// `expr`. method/span lists are sorted with the most recent call first.
959pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {
960    let mut method_names = Vec::with_capacity(max_depth);
961    let mut arg_lists = Vec::with_capacity(max_depth);
962    let mut spans = Vec::with_capacity(max_depth);
963
964    let mut current = expr;
965    for _ in 0..max_depth {
966        if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
967            if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
968                break;
969            }
970            method_names.push(path.ident.name);
971            arg_lists.push((*receiver, &**args));
972            spans.push(path.ident.span);
973            current = receiver;
974        } else {
975            break;
976        }
977    }
978
979    (method_names, arg_lists, spans)
980}
981
982/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
983///
984/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
985/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
986/// containing the `Expr`s for
987/// `.bar()` and `.baz()`
988pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
989    let mut current = expr;
990    let mut matched = Vec::with_capacity(methods.len());
991    for method_name in methods.iter().rev() {
992        // method chains are stored last -> first
993        if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
994            if path.ident.name == *method_name {
995                if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
996                    return None;
997                }
998                matched.push((receiver, args)); // build up `matched` backwards
999                current = receiver; // go to parent expression
1000            } else {
1001                return None;
1002            }
1003        } else {
1004            return None;
1005        }
1006    }
1007    // Reverse `matched` so that it is in the same order as `methods`.
1008    matched.reverse();
1009    Some(matched)
1010}
1011
1012/// Returns `true` if the provided `def_id` is an entrypoint to a program.
1013pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
1014    cx.tcx
1015        .entry_fn(())
1016        .is_some_and(|(entry_fn_def_id, _)| def_id == entry_fn_def_id)
1017}
1018
1019/// Returns `true` if the expression is in the program's `#[panic_handler]`.
1020pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
1021    let parent = cx.tcx.hir_get_parent_item(e.hir_id);
1022    Some(parent.to_def_id()) == cx.tcx.lang_items().panic_impl()
1023}
1024
1025/// Gets the name of the item the expression is in, if available.
1026pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
1027    let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id;
1028    match cx.tcx.hir_node_by_def_id(parent_id) {
1029        Node::Item(item) => item.kind.ident().map(|ident| ident.name),
1030        Node::TraitItem(TraitItem { ident, .. }) | Node::ImplItem(ImplItem { ident, .. }) => Some(ident.name),
1031        _ => None,
1032    }
1033}
1034
1035pub struct ContainsName<'a, 'tcx> {
1036    pub cx: &'a LateContext<'tcx>,
1037    pub name: Symbol,
1038}
1039
1040impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {
1041    type Result = ControlFlow<()>;
1042    type NestedFilter = nested_filter::OnlyBodies;
1043
1044    fn visit_name(&mut self, name: Symbol) -> Self::Result {
1045        if self.name == name {
1046            ControlFlow::Break(())
1047        } else {
1048            ControlFlow::Continue(())
1049        }
1050    }
1051
1052    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
1053        self.cx.tcx
1054    }
1055}
1056
1057/// Checks if an `Expr` contains a certain name.
1058pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {
1059    let mut cn = ContainsName { cx, name };
1060    cn.visit_expr(expr).is_break()
1061}
1062
1063/// Returns `true` if `expr` contains a return expression
1064pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
1065    for_each_expr_without_closures(expr, |e| {
1066        if matches!(e.kind, ExprKind::Ret(..)) {
1067            ControlFlow::Break(())
1068        } else {
1069            ControlFlow::Continue(())
1070        }
1071    })
1072    .is_some()
1073}
1074
1075/// Gets the parent expression, if any –- this is useful to constrain a lint.
1076pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
1077    get_parent_expr_for_hir(cx, e.hir_id)
1078}
1079
1080/// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
1081/// constraint lints
1082pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
1083    match cx.tcx.parent_hir_node(hir_id) {
1084        Node::Expr(parent) => Some(parent),
1085        _ => None,
1086    }
1087}
1088
1089/// Gets the enclosing block, if any.
1090pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
1091    let enclosing_node = cx
1092        .tcx
1093        .hir_get_enclosing_scope(hir_id)
1094        .map(|enclosing_id| cx.tcx.hir_node(enclosing_id));
1095    enclosing_node.and_then(|node| match node {
1096        Node::Block(block) => Some(block),
1097        Node::Item(&Item {
1098            kind: ItemKind::Fn { body: eid, .. },
1099            ..
1100        })
1101        | Node::ImplItem(&ImplItem {
1102            kind: ImplItemKind::Fn(_, eid),
1103            ..
1104        })
1105        | Node::TraitItem(&TraitItem {
1106            kind: TraitItemKind::Fn(_, TraitFn::Provided(eid)),
1107            ..
1108        }) => match cx.tcx.hir_body(eid).value.kind {
1109            ExprKind::Block(block, _) => Some(block),
1110            _ => None,
1111        },
1112        _ => None,
1113    })
1114}
1115
1116/// Gets the loop or closure enclosing the given expression, if any.
1117pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
1118    cx: &LateContext<'tcx>,
1119    expr: &Expr<'_>,
1120) -> Option<&'tcx Expr<'tcx>> {
1121    for (_, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
1122        match node {
1123            Node::Expr(e) => match e.kind {
1124                ExprKind::Closure { .. }
1125                    if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
1126                        && subs.as_closure().kind() == ClosureKind::FnOnce => {},
1127
1128                // Note: A closure's kind is determined by how it's used, not it's captures.
1129                ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
1130                _ => (),
1131            },
1132            Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) | Node::ExprField(_) => (),
1133            _ => break,
1134        }
1135    }
1136    None
1137}
1138
1139/// Gets the parent node if it's an impl block.
1140pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
1141    match tcx.hir_parent_iter(id).next() {
1142        Some((
1143            _,
1144            Node::Item(Item {
1145                kind: ItemKind::Impl(imp),
1146                ..
1147            }),
1148        )) => Some(imp),
1149        _ => None,
1150    }
1151}
1152
1153/// Removes blocks around an expression, only if the block contains just one expression
1154/// and no statements. Unsafe blocks are not removed.
1155///
1156/// Examples:
1157///  * `{}`               -> `{}`
1158///  * `{ x }`            -> `x`
1159///  * `{{ x }}`          -> `x`
1160///  * `{ x; }`           -> `{ x; }`
1161///  * `{ x; y }`         -> `{ x; y }`
1162///  * `{ unsafe { x } }` -> `unsafe { x }`
1163pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
1164    while let ExprKind::Block(
1165        Block {
1166            stmts: [],
1167            expr: Some(inner),
1168            rules: BlockCheckMode::DefaultBlock,
1169            ..
1170        },
1171        _,
1172    ) = expr.kind
1173    {
1174        expr = inner;
1175    }
1176    expr
1177}
1178
1179/// Removes blocks around an expression, only if the block contains just one expression
1180/// or just one expression statement with a semicolon. Unsafe blocks are not removed.
1181///
1182/// Examples:
1183///  * `{}`               -> `{}`
1184///  * `{ x }`            -> `x`
1185///  * `{ x; }`           -> `x`
1186///  * `{{ x; }}`         -> `x`
1187///  * `{ x; y }`         -> `{ x; y }`
1188///  * `{ unsafe { x } }` -> `unsafe { x }`
1189pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
1190    while let ExprKind::Block(
1191        Block {
1192            stmts: [],
1193            expr: Some(inner),
1194            rules: BlockCheckMode::DefaultBlock,
1195            ..
1196        }
1197        | Block {
1198            stmts:
1199                [
1200                    Stmt {
1201                        kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
1202                        ..
1203                    },
1204                ],
1205            expr: None,
1206            rules: BlockCheckMode::DefaultBlock,
1207            ..
1208        },
1209        _,
1210    ) = expr.kind
1211    {
1212        expr = inner;
1213    }
1214    expr
1215}
1216
1217/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
1218pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1219    let mut iter = tcx.hir_parent_iter(expr.hir_id);
1220    match iter.next() {
1221        Some((
1222            _,
1223            Node::Expr(Expr {
1224                kind: ExprKind::If(_, _, Some(else_expr)),
1225                ..
1226            }),
1227        )) => else_expr.hir_id == expr.hir_id,
1228        _ => false,
1229    }
1230}
1231
1232/// Checks if the given expression is a part of `let else`
1233/// returns `true` for both the `init` and the `else` part
1234pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1235    let mut child_id = expr.hir_id;
1236    for (parent_id, node) in tcx.hir_parent_iter(child_id) {
1237        if let Node::LetStmt(LetStmt {
1238            init: Some(init),
1239            els: Some(els),
1240            ..
1241        }) = node
1242            && (init.hir_id == child_id || els.hir_id == child_id)
1243        {
1244            return true;
1245        }
1246
1247        child_id = parent_id;
1248    }
1249
1250    false
1251}
1252
1253/// Checks if the given expression is the else clause of a `let else` expression
1254pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1255    let mut child_id = expr.hir_id;
1256    for (parent_id, node) in tcx.hir_parent_iter(child_id) {
1257        if let Node::LetStmt(LetStmt { els: Some(els), .. }) = node
1258            && els.hir_id == child_id
1259        {
1260            return true;
1261        }
1262
1263        child_id = parent_id;
1264    }
1265
1266    false
1267}
1268
1269/// Checks whether the given `Expr` is a range equivalent to a `RangeFull`.
1270///
1271/// For the lower bound, this means that:
1272/// - either there is none
1273/// - or it is the smallest value that can be represented by the range's integer type
1274///
1275/// For the upper bound, this means that:
1276/// - either there is none
1277/// - or it is the largest value that can be represented by the range's integer type and is
1278///   inclusive
1279/// - or it is a call to some container's `len` method and is exclusive, and the range is passed to
1280///   a method call on that same container (e.g. `v.drain(..v.len())`)
1281///
1282/// If the given `Expr` is not some kind of range, the function returns `false`.
1283pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
1284    let ty = cx.typeck_results().expr_ty(expr);
1285    if let Some(Range { start, end, limits }) = Range::hir(expr) {
1286        let start_is_none_or_min = start.is_none_or(|start| {
1287            if let rustc_ty::Adt(_, subst) = ty.kind()
1288                && let bnd_ty = subst.type_at(0)
1289                && let Some(start_const) = ConstEvalCtxt::new(cx).eval(start)
1290            {
1291                start_const.is_numeric_min(cx.tcx, bnd_ty)
1292            } else {
1293                false
1294            }
1295        });
1296        let end_is_none_or_max = end.is_none_or(|end| match limits {
1297            RangeLimits::Closed => {
1298                if let rustc_ty::Adt(_, subst) = ty.kind()
1299                    && let bnd_ty = subst.type_at(0)
1300                    && let Some(end_const) = ConstEvalCtxt::new(cx).eval(end)
1301                {
1302                    end_const.is_numeric_max(cx.tcx, bnd_ty)
1303                } else {
1304                    false
1305                }
1306            },
1307            RangeLimits::HalfOpen => {
1308                if let Some(container_path) = container_path
1309                    && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind
1310                    && name.ident.name == sym::len
1311                    && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
1312                {
1313                    container_path.res == path.res
1314                } else {
1315                    false
1316                }
1317            },
1318        });
1319        return start_is_none_or_min && end_is_none_or_max;
1320    }
1321    false
1322}
1323
1324/// Checks whether the given expression is a constant integer of the given value.
1325/// unlike `is_integer_literal`, this version does const folding
1326pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
1327    if is_integer_literal(e, value) {
1328        return true;
1329    }
1330    let enclosing_body = cx.tcx.hir_enclosing_body_owner(e.hir_id);
1331    if let Some(Constant::Int(v)) =
1332        ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), cx.tcx.typeck(enclosing_body)).eval(e)
1333    {
1334        return value == v;
1335    }
1336    false
1337}
1338
1339/// Checks whether the given expression is a constant literal of the given value.
1340pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
1341    // FIXME: use constant folding
1342    if let ExprKind::Lit(spanned) = expr.kind
1343        && let LitKind::Int(v, _) = spanned.node
1344    {
1345        return v == value;
1346    }
1347    false
1348}
1349
1350/// Checks whether the given expression is a constant literal of the given value.
1351pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool {
1352    if let ExprKind::Lit(spanned) = expr.kind
1353        && let LitKind::Float(v, _) = spanned.node
1354    {
1355        v.as_str().parse() == Ok(value)
1356    } else {
1357        false
1358    }
1359}
1360
1361/// Returns `true` if the given `Expr` has been coerced before.
1362///
1363/// Examples of coercions can be found in the Nomicon at
1364/// <https://doc.rust-lang.org/nomicon/coercions.html>.
1365///
1366/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::check::coercion` for
1367/// more information on adjustments and coercions.
1368pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
1369    cx.typeck_results().adjustments().get(e.hir_id).is_some()
1370}
1371
1372/// Returns the pre-expansion span if this comes from an expansion of the
1373/// macro `name`.
1374/// See also [`is_direct_expn_of`].
1375#[must_use]
1376pub fn is_expn_of(mut span: Span, name: Symbol) -> Option<Span> {
1377    loop {
1378        if span.from_expansion() {
1379            let data = span.ctxt().outer_expn_data();
1380            let new_span = data.call_site;
1381
1382            if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
1383                && mac_name == name
1384            {
1385                return Some(new_span);
1386            }
1387
1388            span = new_span;
1389        } else {
1390            return None;
1391        }
1392    }
1393}
1394
1395/// Returns the pre-expansion span if the span directly comes from an expansion
1396/// of the macro `name`.
1397/// The difference with [`is_expn_of`] is that in
1398/// ```no_run
1399/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
1400/// # macro_rules! bar { ($e:expr) => { $e } }
1401/// foo!(bar!(42));
1402/// ```
1403/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
1404/// from `bar!` by `is_direct_expn_of`.
1405#[must_use]
1406pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option<Span> {
1407    if span.from_expansion() {
1408        let data = span.ctxt().outer_expn_data();
1409        let new_span = data.call_site;
1410
1411        if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
1412            && mac_name == name
1413        {
1414            return Some(new_span);
1415        }
1416    }
1417
1418    None
1419}
1420
1421/// Convenience function to get the return type of a function.
1422pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId) -> Ty<'tcx> {
1423    let ret_ty = cx.tcx.fn_sig(fn_def_id).instantiate_identity().output();
1424    cx.tcx.instantiate_bound_regions_with_erased(ret_ty)
1425}
1426
1427/// Convenience function to get the nth argument type of a function.
1428pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId, nth: usize) -> Ty<'tcx> {
1429    let arg = cx.tcx.fn_sig(fn_def_id).instantiate_identity().input(nth);
1430    cx.tcx.instantiate_bound_regions_with_erased(arg)
1431}
1432
1433/// Checks if an expression is constructing a tuple-like enum variant or struct
1434pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1435    if let ExprKind::Call(fun, _) = expr.kind
1436        && let ExprKind::Path(ref qp) = fun.kind
1437    {
1438        let res = cx.qpath_res(qp, fun.hir_id);
1439        return match res {
1440            Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
1441            Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
1442            _ => false,
1443        };
1444    }
1445    false
1446}
1447
1448/// Returns `true` if a pattern is refutable.
1449// TODO: should be implemented using rustc/mir_build/thir machinery
1450pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
1451    fn is_qpath_refutable(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
1452        !matches!(
1453            cx.qpath_res(qpath, id),
1454            Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), _)
1455        )
1456    }
1457
1458    fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
1459        i.into_iter().any(|pat| is_refutable(cx, pat))
1460    }
1461
1462    match pat.kind {
1463        PatKind::Missing => unreachable!(),
1464        PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
1465        PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
1466        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
1467        PatKind::Expr(PatExpr {
1468            kind: PatExprKind::Path(qpath),
1469            hir_id,
1470            ..
1471        }) => is_qpath_refutable(cx, qpath, *hir_id),
1472        PatKind::Or(pats) => {
1473            // TODO: should be the honest check, that pats is exhaustive set
1474            are_refutable(cx, pats)
1475        },
1476        PatKind::Tuple(pats, _) => are_refutable(cx, pats),
1477        PatKind::Struct(ref qpath, fields, _) => {
1478            is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))
1479        },
1480        PatKind::TupleStruct(ref qpath, pats, _) => {
1481            is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, pats)
1482        },
1483        PatKind::Slice(head, middle, tail) => {
1484            match &cx.typeck_results().node_type(pat.hir_id).kind() {
1485                rustc_ty::Slice(..) => {
1486                    // [..] is the only irrefutable slice pattern.
1487                    !head.is_empty() || middle.is_none() || !tail.is_empty()
1488                },
1489                rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
1490                _ => {
1491                    // unreachable!()
1492                    true
1493                },
1494            }
1495        },
1496        PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
1497    }
1498}
1499
1500/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
1501/// the function once on the given pattern.
1502pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
1503    if let PatKind::Or(pats) = pat.kind {
1504        pats.iter().for_each(f);
1505    } else {
1506        f(pat);
1507    }
1508}
1509
1510pub fn is_self(slf: &Param<'_>) -> bool {
1511    if let PatKind::Binding(.., name, _) = slf.pat.kind {
1512        name.name == kw::SelfLower
1513    } else {
1514        false
1515    }
1516}
1517
1518pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
1519    if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind
1520        && let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res
1521    {
1522        return true;
1523    }
1524    false
1525}
1526
1527pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
1528    (0..decl.inputs.len()).map(move |i| &body.params[i])
1529}
1530
1531/// Checks if a given expression is a match expression expanded from the `?`
1532/// operator or the `try` macro.
1533pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
1534    fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1535        if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind
1536            && ddpos.as_opt_usize().is_none()
1537            && cx
1538                .qpath_res(path, arm.pat.hir_id)
1539                .ctor_parent(cx)
1540                .is_lang_item(cx, ResultOk)
1541            && let PatKind::Binding(_, hir_id, _, None) = pat[0].kind
1542            && arm.body.res_local_id() == Some(hir_id)
1543        {
1544            return true;
1545        }
1546        false
1547    }
1548
1549    fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1550        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
1551            cx.qpath_res(path, arm.pat.hir_id)
1552                .ctor_parent(cx)
1553                .is_lang_item(cx, ResultErr)
1554        } else {
1555            false
1556        }
1557    }
1558
1559    if let ExprKind::Match(_, arms, ref source) = expr.kind {
1560        // desugared from a `?` operator
1561        if let MatchSource::TryDesugar(_) = *source {
1562            return Some(expr);
1563        }
1564
1565        if arms.len() == 2
1566            && arms[0].guard.is_none()
1567            && arms[1].guard.is_none()
1568            && ((is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0])))
1569        {
1570            return Some(expr);
1571        }
1572    }
1573
1574    None
1575}
1576
1577/// Returns `true` if the lint is `#[allow]`ed or `#[expect]`ed at any of the `ids`, fulfilling all
1578/// of the expectations in `ids`
1579///
1580/// This should only be used when the lint would otherwise be emitted, for a way to check if a lint
1581/// is allowed early to skip work see [`is_lint_allowed`]
1582///
1583/// To emit at a lint at a different context than the one current see
1584/// [`span_lint_hir`](diagnostics::span_lint_hir) or
1585/// [`span_lint_hir_and_then`](diagnostics::span_lint_hir_and_then)
1586pub fn fulfill_or_allowed(cx: &LateContext<'_>, lint: &'static Lint, ids: impl IntoIterator<Item = HirId>) -> bool {
1587    let mut suppress_lint = false;
1588
1589    for id in ids {
1590        let LevelAndSource { level, lint_id, .. } = cx.tcx.lint_level_at_node(lint, id);
1591        if let Some(expectation) = lint_id {
1592            cx.fulfill_expectation(expectation);
1593        }
1594
1595        match level {
1596            Level::Allow | Level::Expect => suppress_lint = true,
1597            Level::Warn | Level::ForceWarn | Level::Deny | Level::Forbid => {},
1598        }
1599    }
1600
1601    suppress_lint
1602}
1603
1604/// Returns `true` if the lint is allowed in the current context. This is useful for
1605/// skipping long running code when it's unnecessary
1606///
1607/// This function should check the lint level for the same node, that the lint will
1608/// be emitted at. If the information is buffered to be emitted at a later point, please
1609/// make sure to use `span_lint_hir` functions to emit the lint. This ensures that
1610/// expectations at the checked nodes will be fulfilled.
1611pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
1612    cx.tcx.lint_level_at_node(lint, id).level == Level::Allow
1613}
1614
1615pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
1616    while let PatKind::Ref(subpat, _) = pat.kind {
1617        pat = subpat;
1618    }
1619    pat
1620}
1621
1622pub fn int_bits(tcx: TyCtxt<'_>, ity: IntTy) -> u64 {
1623    Integer::from_int_ty(&tcx, ity).size().bits()
1624}
1625
1626#[expect(clippy::cast_possible_wrap)]
1627/// Turn a constant int byte representation into an i128
1628pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: IntTy) -> i128 {
1629    let amt = 128 - int_bits(tcx, ity);
1630    ((u as i128) << amt) >> amt
1631}
1632
1633#[expect(clippy::cast_sign_loss)]
1634/// clip unused bytes
1635pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: IntTy) -> u128 {
1636    let amt = 128 - int_bits(tcx, ity);
1637    ((u as u128) << amt) >> amt
1638}
1639
1640/// clip unused bytes
1641pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: UintTy) -> u128 {
1642    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
1643    let amt = 128 - bits;
1644    (u << amt) >> amt
1645}
1646
1647pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool {
1648    attrs.iter().any(|attr| attr.has_name(symbol))
1649}
1650
1651pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
1652    find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr { .. })
1653}
1654
1655pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
1656    let mut prev_enclosing_node = None;
1657    let mut enclosing_node = node;
1658    while Some(enclosing_node) != prev_enclosing_node {
1659        if has_attr(tcx.hir_attrs(enclosing_node), symbol) {
1660            return true;
1661        }
1662        prev_enclosing_node = Some(enclosing_node);
1663        enclosing_node = tcx.hir_get_parent_item(enclosing_node).into();
1664    }
1665
1666    false
1667}
1668
1669/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived`
1670/// attribute.
1671pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
1672    tcx.hir_parent_owner_iter(id)
1673        .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_))))
1674        .any(|(id, _)| {
1675            find_attr!(
1676                tcx.hir_attrs(tcx.local_def_id_to_hir_id(id.def_id)),
1677                AttributeKind::AutomaticallyDerived(..)
1678            )
1679        })
1680}
1681
1682/// Checks if the given `DefId` matches the `libc` item.
1683pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool {
1684    // libc is meant to be used as a flat list of names, but they're all actually defined in different
1685    // modules based on the target platform. Ignore everything but crate name and the item name.
1686    cx.tcx.crate_name(did.krate) == sym::libc && cx.tcx.def_path_str(did).ends_with(name.as_str())
1687}
1688
1689/// Returns the list of condition expressions and the list of blocks in a
1690/// sequence of `if/else`.
1691/// E.g., this returns `([a, b], [c, d, e])` for the expression
1692/// `if a { c } else if b { d } else { e }`.
1693pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {
1694    let mut conds = Vec::new();
1695    let mut blocks: Vec<&Block<'_>> = Vec::new();
1696
1697    while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {
1698        conds.push(cond);
1699        if let ExprKind::Block(block, _) = then.kind {
1700            blocks.push(block);
1701        } else {
1702            panic!("ExprKind::If node is not an ExprKind::Block");
1703        }
1704
1705        if let Some(else_expr) = r#else {
1706            expr = else_expr;
1707        } else {
1708            break;
1709        }
1710    }
1711
1712    // final `else {..}`
1713    if !blocks.is_empty()
1714        && let ExprKind::Block(block, _) = expr.kind
1715    {
1716        blocks.push(block);
1717    }
1718
1719    (conds, blocks)
1720}
1721
1722/// Peels away all the compiler generated code surrounding the body of an async closure.
1723pub fn get_async_closure_expr<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
1724    if let ExprKind::Closure(&Closure {
1725        body,
1726        kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
1727        ..
1728    }) = expr.kind
1729        && let ExprKind::Block(
1730            Block {
1731                expr:
1732                    Some(Expr {
1733                        kind: ExprKind::DropTemps(inner_expr),
1734                        ..
1735                    }),
1736                ..
1737            },
1738            _,
1739        ) = tcx.hir_body(body).value.kind
1740    {
1741        Some(inner_expr)
1742    } else {
1743        None
1744    }
1745}
1746
1747/// Peels away all the compiler generated code surrounding the body of an async function,
1748pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
1749    get_async_closure_expr(tcx, body.value)
1750}
1751
1752// check if expr is calling method or function with #[must_use] attribute
1753pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1754    let did = match expr.kind {
1755        ExprKind::Call(path, _) => {
1756            if let ExprKind::Path(ref qpath) = path.kind
1757                && let Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id)
1758            {
1759                Some(did)
1760            } else {
1761                None
1762            }
1763        },
1764        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
1765        _ => None,
1766    };
1767
1768    did.is_some_and(|did| find_attr!(cx.tcx.get_all_attrs(did), AttributeKind::MustUse { .. }))
1769}
1770
1771/// Checks if a function's body represents the identity function. Looks for bodies of the form:
1772/// * `|x| x`
1773/// * `|x| return x`
1774/// * `|x| { return x }`
1775/// * `|x| { return x; }`
1776/// * `|(x, y)| (x, y)`
1777/// * `|[x, y]| [x, y]`
1778/// * `|Foo(bar, baz)| Foo(bar, baz)`
1779/// * `|Foo { bar, baz }| Foo { bar, baz }`
1780///
1781/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
1782fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
1783    let [param] = func.params else {
1784        return false;
1785    };
1786
1787    let mut expr = func.value;
1788    loop {
1789        match expr.kind {
1790            ExprKind::Block(
1791                &Block {
1792                    stmts: [],
1793                    expr: Some(e),
1794                    ..
1795                },
1796                _,
1797            )
1798            | ExprKind::Ret(Some(e)) => expr = e,
1799            ExprKind::Block(
1800                &Block {
1801                    stmts: [stmt],
1802                    expr: None,
1803                    ..
1804                },
1805                _,
1806            ) => {
1807                if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind
1808                    && let ExprKind::Ret(Some(ret_val)) = e.kind
1809                {
1810                    expr = ret_val;
1811                } else {
1812                    return false;
1813                }
1814            },
1815            _ => return is_expr_identity_of_pat(cx, param.pat, expr, true),
1816        }
1817    }
1818}
1819
1820/// Checks if the given expression is an identity representation of the given pattern:
1821/// * `x` is the identity representation of `x`
1822/// * `(x, y)` is the identity representation of `(x, y)`
1823/// * `[x, y]` is the identity representation of `[x, y]`
1824/// * `Foo(bar, baz)` is the identity representation of `Foo(bar, baz)`
1825/// * `Foo { bar, baz }` is the identity representation of `Foo { bar, baz }`
1826///
1827/// Note that `by_hir` is used to determine bindings are checked by their `HirId` or by their name.
1828/// This can be useful when checking patterns in `let` bindings or `match` arms.
1829pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>, by_hir: bool) -> bool {
1830    if cx
1831        .typeck_results()
1832        .pat_binding_modes()
1833        .get(pat.hir_id)
1834        .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
1835    {
1836        // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
1837        // due to match ergonomics, the inner patterns become references. Don't consider this
1838        // the identity function as that changes types.
1839        return false;
1840    }
1841
1842    // NOTE: we're inside a (function) body, so this won't ICE
1843    let qpath_res = |qpath, hir| cx.typeck_results().qpath_res(qpath, hir);
1844
1845    match (pat.kind, expr.kind) {
1846        (PatKind::Binding(_, id, _, _), _) if by_hir => {
1847            expr.res_local_id() == Some(id) && cx.typeck_results().expr_adjustments(expr).is_empty()
1848        },
1849        (PatKind::Binding(_, _, ident, _), ExprKind::Path(QPath::Resolved(_, path))) => {
1850            matches!(path.segments, [ segment] if segment.ident.name == ident.name)
1851        },
1852        (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup))
1853            if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() =>
1854        {
1855            over(pats, tup, |pat, expr| is_expr_identity_of_pat(cx, pat, expr, by_hir))
1856        },
1857        (PatKind::Slice(before, None, after), ExprKind::Array(arr)) if before.len() + after.len() == arr.len() => {
1858            zip(before.iter().chain(after), arr).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr, by_hir))
1859        },
1860        (PatKind::TupleStruct(pat_ident, field_pats, dotdot), ExprKind::Call(ident, fields))
1861            if dotdot.as_opt_usize().is_none() && field_pats.len() == fields.len() =>
1862        {
1863            // check ident
1864            if let ExprKind::Path(ident) = &ident.kind
1865                && qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id)
1866                // check fields
1867                && over(field_pats, fields, |pat, expr| is_expr_identity_of_pat(cx, pat, expr,by_hir))
1868            {
1869                true
1870            } else {
1871                false
1872            }
1873        },
1874        (PatKind::Struct(pat_ident, field_pats, None), ExprKind::Struct(ident, fields, hir::StructTailExpr::None))
1875            if field_pats.len() == fields.len() =>
1876        {
1877            // check ident
1878            qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id)
1879                // check fields
1880                && unordered_over(field_pats, fields, |field_pat, field| {
1881                    field_pat.ident == field.ident && is_expr_identity_of_pat(cx, field_pat.pat, field.expr, by_hir)
1882                })
1883        },
1884        _ => false,
1885    }
1886}
1887
1888/// This is the same as [`is_expr_identity_function`], but does not consider closures
1889/// with type annotations for its bindings (or similar) as identity functions:
1890/// * `|x: u8| x`
1891/// * `std::convert::identity::<u8>`
1892pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1893    match expr.kind {
1894        ExprKind::Closure(&Closure { body, fn_decl, .. })
1895            if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) =>
1896        {
1897            is_body_identity_function(cx, cx.tcx.hir_body(body))
1898        },
1899        ExprKind::Path(QPath::Resolved(_, path))
1900            if path.segments.iter().all(|seg| seg.infer_args)
1901                && let Some(did) = path.res.opt_def_id() =>
1902        {
1903            cx.tcx.is_diagnostic_item(sym::convert_identity, did)
1904        },
1905        _ => false,
1906    }
1907}
1908
1909/// Checks if an expression represents the identity function
1910/// Only examines closures and `std::convert::identity`
1911///
1912/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want
1913/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't
1914/// have type annotations. This is important because removing a closure with bindings can
1915/// remove type information that helped type inference before, which can then lead to compile
1916/// errors.
1917pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1918    match expr.kind {
1919        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir_body(body)),
1920        _ => expr.basic_res().is_diag_item(cx, sym::convert_identity),
1921    }
1922}
1923
1924/// Gets the node where an expression is either used, or it's type is unified with another branch.
1925/// Returns both the node and the `HirId` of the closest child node.
1926pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
1927    let mut child_id = expr.hir_id;
1928    let mut iter = tcx.hir_parent_iter(child_id);
1929    loop {
1930        match iter.next() {
1931            None => break None,
1932            Some((id, Node::Block(_))) => child_id = id,
1933            Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
1934            Some((_, Node::Expr(expr))) => match expr.kind {
1935                ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
1936                ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
1937                ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
1938                _ => break Some((Node::Expr(expr), child_id)),
1939            },
1940            Some((_, node)) => break Some((node, child_id)),
1941        }
1942    }
1943}
1944
1945/// Checks if the result of an expression is used, or it's type is unified with another branch.
1946pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1947    !matches!(
1948        get_expr_use_or_unification_node(tcx, expr),
1949        None | Some((
1950            Node::Stmt(Stmt {
1951                kind: StmtKind::Expr(_)
1952                    | StmtKind::Semi(_)
1953                    | StmtKind::Let(LetStmt {
1954                        pat: Pat {
1955                            kind: PatKind::Wild,
1956                            ..
1957                        },
1958                        ..
1959                    }),
1960                ..
1961            }),
1962            _
1963        ))
1964    )
1965}
1966
1967/// Checks if the expression is the final expression returned from a block.
1968pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1969    matches!(tcx.parent_hir_node(expr.hir_id), Node::Block(..))
1970}
1971
1972/// Checks if the expression is a temporary value.
1973// This logic is the same as the one used in rustc's `check_named_place_expr function`.
1974// https://github.com/rust-lang/rust/blob/3ed2a10d173d6c2e0232776af338ca7d080b1cd4/compiler/rustc_hir_typeck/src/expr.rs#L482-L499
1975pub fn is_expr_temporary_value(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1976    !expr.is_place_expr(|base| {
1977        cx.typeck_results()
1978            .adjustments()
1979            .get(base.hir_id)
1980            .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
1981    })
1982}
1983
1984pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
1985    if !is_no_std_crate(cx) {
1986        Some("std")
1987    } else if !is_no_core_crate(cx) {
1988        Some("core")
1989    } else {
1990        None
1991    }
1992}
1993
1994pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
1995    find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::NoStd(..))
1996}
1997
1998pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
1999    find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::NoCore(..))
2000}
2001
2002/// Check if parent of a hir node is a trait implementation block.
2003/// For example, `f` in
2004/// ```no_run
2005/// # struct S;
2006/// # trait Trait { fn f(); }
2007/// impl Trait for S {
2008///     fn f() {}
2009/// }
2010/// ```
2011pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
2012    if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
2013        matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }))
2014    } else {
2015        false
2016    }
2017}
2018
2019/// Check if it's even possible to satisfy the `where` clause for the item.
2020///
2021/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
2022///
2023/// ```ignore
2024/// fn foo() where i32: Iterator {
2025///     for _ in 2i32 {}
2026/// }
2027/// ```
2028pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
2029    use rustc_trait_selection::traits;
2030    let predicates = cx
2031        .tcx
2032        .predicates_of(did)
2033        .predicates
2034        .iter()
2035        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
2036    traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
2037}
2038
2039/// Returns the `DefId` of the callee if the given expression is a function or method call.
2040pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
2041    fn_def_id_with_node_args(cx, expr).map(|(did, _)| did)
2042}
2043
2044/// Returns the `DefId` of the callee if the given expression is a function or method call,
2045/// as well as its node args.
2046pub fn fn_def_id_with_node_args<'tcx>(
2047    cx: &LateContext<'tcx>,
2048    expr: &Expr<'_>,
2049) -> Option<(DefId, GenericArgsRef<'tcx>)> {
2050    let typeck = cx.typeck_results();
2051    match &expr.kind {
2052        ExprKind::MethodCall(..) => Some((
2053            typeck.type_dependent_def_id(expr.hir_id)?,
2054            typeck.node_args(expr.hir_id),
2055        )),
2056        ExprKind::Call(
2057            Expr {
2058                kind: ExprKind::Path(qpath),
2059                hir_id: path_hir_id,
2060                ..
2061            },
2062            ..,
2063        ) => {
2064            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
2065            // deref to fn pointers, dyn Fn, impl Fn - #8850
2066            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
2067                typeck.qpath_res(qpath, *path_hir_id)
2068            {
2069                Some((id, typeck.node_args(*path_hir_id)))
2070            } else {
2071                None
2072            }
2073        },
2074        _ => None,
2075    }
2076}
2077
2078/// Returns `Option<String>` where String is a textual representation of the type encapsulated in
2079/// the slice iff the given expression is a slice of primitives.
2080///
2081/// (As defined in the `is_recursively_primitive_type` function.) Returns `None` otherwise.
2082pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
2083    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
2084    let expr_kind = expr_type.kind();
2085    let is_primitive = match expr_kind {
2086        rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type),
2087        rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
2088            if let rustc_ty::Slice(element_type) = inner_ty.kind() {
2089                is_recursively_primitive_type(*element_type)
2090            } else {
2091                unreachable!()
2092            }
2093        },
2094        _ => false,
2095    };
2096
2097    if is_primitive {
2098        // if we have wrappers like Array, Slice or Tuple, print these
2099        // and get the type enclosed in the slice ref
2100        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
2101            rustc_ty::Slice(..) => return Some("slice".into()),
2102            rustc_ty::Array(..) => return Some("array".into()),
2103            rustc_ty::Tuple(..) => return Some("tuple".into()),
2104            _ => {
2105                // is_recursively_primitive_type() should have taken care
2106                // of the rest and we can rely on the type that is found
2107                let refs_peeled = expr_type.peel_refs();
2108                return Some(refs_peeled.walk().last().unwrap().to_string());
2109            },
2110        }
2111    }
2112    None
2113}
2114
2115/// Returns a list of groups where elements in each group are equal according to `eq`
2116///
2117/// - Within each group the elements are sorted by the order they appear in `exprs`
2118/// - The groups themselves are sorted by their first element's appearence in `exprs`
2119///
2120/// Given functions `eq` and `hash` such that `eq(a, b) == true`
2121/// implies `hash(a) == hash(b)`
2122pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<Vec<&T>>
2123where
2124    Hash: FnMut(&T) -> u64,
2125    Eq: FnMut(&T, &T) -> bool,
2126{
2127    match exprs {
2128        [a, b] if eq(a, b) => return vec![vec![a, b]],
2129        _ if exprs.len() <= 2 => return vec![],
2130        _ => {},
2131    }
2132
2133    let mut buckets: UnindexMap<u64, Vec<Vec<&T>>> = UnindexMap::default();
2134
2135    for expr in exprs {
2136        match buckets.entry(hash(expr)) {
2137            indexmap::map::Entry::Occupied(mut o) => {
2138                let bucket = o.get_mut();
2139                match bucket.iter_mut().find(|group| eq(expr, group[0])) {
2140                    Some(group) => group.push(expr),
2141                    None => bucket.push(vec![expr]),
2142                }
2143            },
2144            indexmap::map::Entry::Vacant(v) => {
2145                v.insert(vec![vec![expr]]);
2146            },
2147        }
2148    }
2149
2150    buckets
2151        .into_values()
2152        .flatten()
2153        .filter(|group| group.len() > 1)
2154        .collect()
2155}
2156
2157/// Peels off all references on the pattern. Returns the underlying pattern and the number of
2158/// references removed.
2159pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
2160    fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
2161        if let PatKind::Ref(pat, _) = pat.kind {
2162            peel(pat, count + 1)
2163        } else {
2164            (pat, count)
2165        }
2166    }
2167    peel(pat, 0)
2168}
2169
2170/// Peels of expressions while the given closure returns `Some`.
2171pub fn peel_hir_expr_while<'tcx>(
2172    mut expr: &'tcx Expr<'tcx>,
2173    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
2174) -> &'tcx Expr<'tcx> {
2175    while let Some(e) = f(expr) {
2176        expr = e;
2177    }
2178    expr
2179}
2180
2181/// Peels off up to the given number of references on the expression. Returns the underlying
2182/// expression and the number of references removed.
2183pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
2184    let mut remaining = count;
2185    let e = peel_hir_expr_while(expr, |e| match e.kind {
2186        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
2187            remaining -= 1;
2188            Some(e)
2189        },
2190        _ => None,
2191    });
2192    (e, count - remaining)
2193}
2194
2195/// Peels off all unary operators of an expression. Returns the underlying expression and the number
2196/// of operators removed.
2197pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2198    let mut count: usize = 0;
2199    let mut curr_expr = expr;
2200    while let ExprKind::Unary(_, local_expr) = curr_expr.kind {
2201        count = count.wrapping_add(1);
2202        curr_expr = local_expr;
2203    }
2204    (curr_expr, count)
2205}
2206
2207/// Peels off all references on the expression. Returns the underlying expression and the number of
2208/// references removed.
2209pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2210    let mut count = 0;
2211    let e = peel_hir_expr_while(expr, |e| match e.kind {
2212        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
2213            count += 1;
2214            Some(e)
2215        },
2216        _ => None,
2217    });
2218    (e, count)
2219}
2220
2221/// Peels off all references on the type. Returns the underlying type and the number of references
2222/// removed.
2223pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) {
2224    let mut count = 0;
2225    loop {
2226        match &ty.kind {
2227            TyKind::Ref(_, ref_ty) => {
2228                ty = ref_ty.ty;
2229                count += 1;
2230            },
2231            _ => break (ty, count),
2232        }
2233    }
2234}
2235
2236/// Returns the base type for HIR references and pointers.
2237pub fn peel_hir_ty_refs_and_ptrs<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
2238    match &ty.kind {
2239        TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => peel_hir_ty_refs_and_ptrs(mut_ty.ty),
2240        _ => ty,
2241    }
2242}
2243
2244/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
2245/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
2246pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
2247    loop {
2248        match expr.kind {
2249            ExprKind::AddrOf(_, _, e) => expr = e,
2250            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
2251            _ => break,
2252        }
2253    }
2254    expr
2255}
2256
2257/// Returns a `Vec` of `Expr`s containing `AddrOf` operators (`&`) or deref operators (`*`) of a
2258/// given expression.
2259pub fn get_ref_operators<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Vec<&'hir Expr<'hir>> {
2260    let mut operators = Vec::new();
2261    peel_hir_expr_while(expr, |expr| match expr.kind {
2262        ExprKind::AddrOf(_, _, e) => {
2263            operators.push(expr);
2264            Some(e)
2265        },
2266        ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => {
2267            operators.push(expr);
2268            Some(e)
2269        },
2270        _ => None,
2271    });
2272    operators
2273}
2274
2275pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
2276    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
2277        && let Res::Def(_, def_id) = path.res
2278    {
2279        return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
2280    }
2281    false
2282}
2283
2284static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalModDefId, Vec<Symbol>>>> = OnceLock::new();
2285
2286/// Apply `f()` to the set of test item names.
2287/// The names are sorted using the default `Symbol` ordering.
2288fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&[Symbol]) -> bool) -> bool {
2289    let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
2290    let mut map: MutexGuard<'_, FxHashMap<LocalModDefId, Vec<Symbol>>> = cache.lock().unwrap();
2291    let value = map.entry(module);
2292    match value {
2293        Entry::Occupied(entry) => f(entry.get()),
2294        Entry::Vacant(entry) => {
2295            let mut names = Vec::new();
2296            for id in tcx.hir_module_free_items(module) {
2297                if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
2298                    && let item = tcx.hir_item(id)
2299                    && let ItemKind::Const(ident, _generics, ty, _body) = item.kind
2300                    && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
2301                        // We could also check for the type name `test::TestDescAndFn`
2302                        && let Res::Def(DefKind::Struct, _) = path.res
2303                {
2304                    let has_test_marker = tcx
2305                        .hir_attrs(item.hir_id())
2306                        .iter()
2307                        .any(|a| a.has_name(sym::rustc_test_marker));
2308                    if has_test_marker {
2309                        names.push(ident.name);
2310                    }
2311                }
2312            }
2313            names.sort_unstable();
2314            f(entry.insert(names))
2315        },
2316    }
2317}
2318
2319/// Checks if the function containing the given `HirId` is a `#[test]` function
2320///
2321/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
2322pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
2323    with_test_item_names(tcx, tcx.parent_module(id), |names| {
2324        let node = tcx.hir_node(id);
2325        once((id, node))
2326            .chain(tcx.hir_parent_iter(id))
2327            // Since you can nest functions we need to collect all until we leave
2328            // function scope
2329            .any(|(_id, node)| {
2330                if let Node::Item(item) = node
2331                    && let ItemKind::Fn { ident, .. } = item.kind
2332                {
2333                    // Note that we have sorted the item names in the visitor,
2334                    // so the binary_search gets the same as `contains`, but faster.
2335                    return names.binary_search(&ident.name).is_ok();
2336                }
2337                false
2338            })
2339    })
2340}
2341
2342/// Checks if `fn_def_id` has a `#[test]` attribute applied
2343///
2344/// This only checks directly applied attributes. To see if a node has a parent function marked with
2345/// `#[test]` use [`is_in_test_function`].
2346///
2347/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
2348pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool {
2349    let id = tcx.local_def_id_to_hir_id(fn_def_id);
2350    if let Node::Item(item) = tcx.hir_node(id)
2351        && let ItemKind::Fn { ident, .. } = item.kind
2352    {
2353        with_test_item_names(tcx, tcx.parent_module(id), |names| {
2354            names.binary_search(&ident.name).is_ok()
2355        })
2356    } else {
2357        false
2358    }
2359}
2360
2361/// Checks if `id` has a `#[cfg(test)]` attribute applied
2362///
2363/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
2364/// use [`is_in_cfg_test`]
2365pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
2366    tcx.hir_attrs(id).iter().any(|attr| {
2367        if attr.has_name(sym::cfg_trace)
2368            && let Some(items) = attr.meta_item_list()
2369            && let [item] = &*items
2370            && item.has_name(sym::test)
2371        {
2372            true
2373        } else {
2374            false
2375        }
2376    })
2377}
2378
2379/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
2380pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
2381    tcx.hir_parent_id_iter(id).any(|parent_id| is_cfg_test(tcx, parent_id))
2382}
2383
2384/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]`
2385pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
2386    is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id)
2387}
2388
2389/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
2390pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
2391    tcx.has_attr(def_id, sym::cfg_trace)
2392        || tcx
2393            .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
2394            .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id))
2395            .any(|attr| attr.has_name(sym::cfg_trace))
2396}
2397
2398/// Walks up the HIR tree from the given expression in an attempt to find where the value is
2399/// consumed.
2400///
2401/// Termination has three conditions:
2402/// - The given function returns `Break`. This function will return the value.
2403/// - The consuming node is found. This function will return `Continue(use_node, child_id)`.
2404/// - No further parent nodes are found. This will trigger a debug assert or return `None`.
2405///
2406/// This allows walking through `if`, `match`, `break`, and block expressions to find where the
2407/// value produced by the expression is consumed.
2408pub fn walk_to_expr_usage<'tcx, T>(
2409    cx: &LateContext<'tcx>,
2410    e: &Expr<'tcx>,
2411    mut f: impl FnMut(HirId, Node<'tcx>, HirId) -> ControlFlow<T>,
2412) -> Option<ControlFlow<T, (Node<'tcx>, HirId)>> {
2413    let mut iter = cx.tcx.hir_parent_iter(e.hir_id);
2414    let mut child_id = e.hir_id;
2415
2416    while let Some((parent_id, parent)) = iter.next() {
2417        if let ControlFlow::Break(x) = f(parent_id, parent, child_id) {
2418            return Some(ControlFlow::Break(x));
2419        }
2420        let parent_expr = match parent {
2421            Node::Expr(e) => e,
2422            Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
2423                child_id = parent_id;
2424                continue;
2425            },
2426            Node::Arm(a) if a.body.hir_id == child_id => {
2427                child_id = parent_id;
2428                continue;
2429            },
2430            _ => return Some(ControlFlow::Continue((parent, child_id))),
2431        };
2432        match parent_expr.kind {
2433            ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
2434            ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
2435                child_id = id;
2436                iter = cx.tcx.hir_parent_iter(id);
2437            },
2438            ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = parent_id,
2439            _ => return Some(ControlFlow::Continue((parent, child_id))),
2440        }
2441    }
2442    debug_assert!(false, "no parent node found for `{child_id:?}`");
2443    None
2444}
2445
2446/// A type definition as it would be viewed from within a function.
2447#[derive(Clone, Copy)]
2448pub enum DefinedTy<'tcx> {
2449    // Used for locals and closures defined within the function.
2450    Hir(&'tcx hir::Ty<'tcx>),
2451    /// Used for function signatures, and constant and static values. The type is
2452    /// in the context of its definition site. We also track the `def_id` of its
2453    /// definition site.
2454    ///
2455    /// WARNING: As the `ty` in in the scope of the definition, not of the function
2456    /// using it, you must be very careful with how you use it. Using it in the wrong
2457    /// scope easily results in ICEs.
2458    Mir {
2459        def_site_def_id: Option<DefId>,
2460        ty: Binder<'tcx, Ty<'tcx>>,
2461    },
2462}
2463
2464/// The context an expressions value is used in.
2465pub struct ExprUseCtxt<'tcx> {
2466    /// The parent node which consumes the value.
2467    pub node: Node<'tcx>,
2468    /// The child id of the node the value came from.
2469    pub child_id: HirId,
2470    /// Any adjustments applied to the type.
2471    pub adjustments: &'tcx [Adjustment<'tcx>],
2472    /// Whether the type must unify with another code path.
2473    pub is_ty_unified: bool,
2474    /// Whether the value will be moved before it's used.
2475    pub moved_before_use: bool,
2476    /// Whether the use site has the same `SyntaxContext` as the value.
2477    pub same_ctxt: bool,
2478}
2479impl<'tcx> ExprUseCtxt<'tcx> {
2480    pub fn use_node(&self, cx: &LateContext<'tcx>) -> ExprUseNode<'tcx> {
2481        match self.node {
2482            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
2483            Node::ExprField(field) => ExprUseNode::Field(field),
2484
2485            Node::Item(&Item {
2486                kind: ItemKind::Static(..) | ItemKind::Const(..),
2487                owner_id,
2488                ..
2489            })
2490            | Node::TraitItem(&TraitItem {
2491                kind: TraitItemKind::Const(..),
2492                owner_id,
2493                ..
2494            })
2495            | Node::ImplItem(&ImplItem {
2496                kind: ImplItemKind::Const(..),
2497                owner_id,
2498                ..
2499            }) => ExprUseNode::ConstStatic(owner_id),
2500
2501            Node::Item(&Item {
2502                kind: ItemKind::Fn { .. },
2503                owner_id,
2504                ..
2505            })
2506            | Node::TraitItem(&TraitItem {
2507                kind: TraitItemKind::Fn(..),
2508                owner_id,
2509                ..
2510            })
2511            | Node::ImplItem(&ImplItem {
2512                kind: ImplItemKind::Fn(..),
2513                owner_id,
2514                ..
2515            }) => ExprUseNode::Return(owner_id),
2516
2517            Node::Expr(use_expr) => match use_expr.kind {
2518                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
2519                    def_id: cx.tcx.hir_body_owner_def_id(cx.enclosing_body.unwrap()),
2520                }),
2521
2522                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
2523                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == self.child_id) {
2524                    Some(i) => ExprUseNode::FnArg(func, i),
2525                    None => ExprUseNode::Callee,
2526                },
2527                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
2528                    use_expr.hir_id,
2529                    name.args,
2530                    args.iter()
2531                        .position(|arg| arg.hir_id == self.child_id)
2532                        .map_or(0, |i| i + 1),
2533                ),
2534                ExprKind::Field(_, name) => ExprUseNode::FieldAccess(name),
2535                ExprKind::AddrOf(kind, mutbl, _) => ExprUseNode::AddrOf(kind, mutbl),
2536                _ => ExprUseNode::Other,
2537            },
2538            _ => ExprUseNode::Other,
2539        }
2540    }
2541}
2542
2543/// The node which consumes a value.
2544pub enum ExprUseNode<'tcx> {
2545    /// Assignment to, or initializer for, a local
2546    LetStmt(&'tcx LetStmt<'tcx>),
2547    /// Initializer for a const or static item.
2548    ConstStatic(OwnerId),
2549    /// Implicit or explicit return from a function.
2550    Return(OwnerId),
2551    /// Initialization of a struct field.
2552    Field(&'tcx ExprField<'tcx>),
2553    /// An argument to a function.
2554    FnArg(&'tcx Expr<'tcx>, usize),
2555    /// An argument to a method.
2556    MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
2557    /// The callee of a function call.
2558    Callee,
2559    /// Access of a field.
2560    FieldAccess(Ident),
2561    /// Borrow expression.
2562    AddrOf(ast::BorrowKind, Mutability),
2563    Other,
2564}
2565impl<'tcx> ExprUseNode<'tcx> {
2566    /// Checks if the value is returned from the function.
2567    pub fn is_return(&self) -> bool {
2568        matches!(self, Self::Return(_))
2569    }
2570
2571    /// Checks if the value is used as a method call receiver.
2572    pub fn is_recv(&self) -> bool {
2573        matches!(self, Self::MethodArg(_, _, 0))
2574    }
2575
2576    /// Gets the needed type as it's defined without any type inference.
2577    pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
2578        match *self {
2579            Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
2580            Self::ConstStatic(id) => Some(DefinedTy::Mir {
2581                def_site_def_id: Some(id.def_id.to_def_id()),
2582                ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()),
2583            }),
2584            Self::Return(id) => {
2585                if let Node::Expr(Expr {
2586                    kind: ExprKind::Closure(c),
2587                    ..
2588                }) = cx.tcx.hir_node_by_def_id(id.def_id)
2589                {
2590                    match c.fn_decl.output {
2591                        FnRetTy::DefaultReturn(_) => None,
2592                        FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
2593                    }
2594                } else {
2595                    let ty = cx.tcx.fn_sig(id).instantiate_identity().output();
2596                    Some(DefinedTy::Mir {
2597                        def_site_def_id: Some(id.def_id.to_def_id()),
2598                        ty,
2599                    })
2600                }
2601            },
2602            Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
2603                Some(Expr {
2604                    hir_id,
2605                    kind: ExprKind::Struct(path, ..),
2606                    ..
2607                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
2608                    .and_then(|(adt, variant)| {
2609                        variant
2610                            .fields
2611                            .iter()
2612                            .find(|f| f.name == field.ident.name)
2613                            .map(|f| (adt, f))
2614                    })
2615                    .map(|(adt, field_def)| DefinedTy::Mir {
2616                        def_site_def_id: Some(adt.did()),
2617                        ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()),
2618                    }),
2619                _ => None,
2620            },
2621            Self::FnArg(callee, i) => {
2622                let sig = expr_sig(cx, callee)?;
2623                let (hir_ty, ty) = sig.input_with_hir(i)?;
2624                Some(match hir_ty {
2625                    Some(hir_ty) => DefinedTy::Hir(hir_ty),
2626                    None => DefinedTy::Mir {
2627                        def_site_def_id: sig.predicates_id(),
2628                        ty,
2629                    },
2630                })
2631            },
2632            Self::MethodArg(id, _, i) => {
2633                let id = cx.typeck_results().type_dependent_def_id(id)?;
2634                let sig = cx.tcx.fn_sig(id).skip_binder();
2635                Some(DefinedTy::Mir {
2636                    def_site_def_id: Some(id),
2637                    ty: sig.input(i),
2638                })
2639            },
2640            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None,
2641        }
2642    }
2643}
2644
2645/// Gets the context an expression's value is used in.
2646pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtxt<'tcx> {
2647    let mut adjustments = [].as_slice();
2648    let mut is_ty_unified = false;
2649    let mut moved_before_use = false;
2650    let mut same_ctxt = true;
2651    let ctxt = e.span.ctxt();
2652    let node = walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| -> ControlFlow<!> {
2653        if adjustments.is_empty()
2654            && let Node::Expr(e) = cx.tcx.hir_node(child_id)
2655        {
2656            adjustments = cx.typeck_results().expr_adjustments(e);
2657        }
2658        same_ctxt &= cx.tcx.hir_span(parent_id).ctxt() == ctxt;
2659        if let Node::Expr(e) = parent {
2660            match e.kind {
2661                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
2662                    is_ty_unified = true;
2663                    moved_before_use = true;
2664                },
2665                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
2666                    is_ty_unified = true;
2667                    moved_before_use = true;
2668                },
2669                ExprKind::Block(..) => moved_before_use = true,
2670                _ => {},
2671            }
2672        }
2673        ControlFlow::Continue(())
2674    });
2675    match node {
2676        Some(ControlFlow::Continue((node, child_id))) => ExprUseCtxt {
2677            node,
2678            child_id,
2679            adjustments,
2680            is_ty_unified,
2681            moved_before_use,
2682            same_ctxt,
2683        },
2684        Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
2685        None => ExprUseCtxt {
2686            node: Node::Crate(cx.tcx.hir_root_module()),
2687            child_id: HirId::INVALID,
2688            adjustments: &[],
2689            is_ty_unified: true,
2690            moved_before_use: true,
2691            same_ctxt: false,
2692        },
2693    }
2694}
2695
2696/// Tokenizes the input while keeping the text associated with each token.
2697pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, InnerSpan)> {
2698    let mut pos = 0;
2699    tokenize(s, FrontmatterAllowed::No).map(move |t| {
2700        let end = pos + t.len;
2701        let range = pos as usize..end as usize;
2702        let inner = InnerSpan::new(range.start, range.end);
2703        pos = end;
2704        (t.kind, s.get(range).unwrap_or_default(), inner)
2705    })
2706}
2707
2708/// Checks whether a given span has any comment token
2709/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
2710pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
2711    let Ok(snippet) = sm.span_to_snippet(span) else {
2712        return false;
2713    };
2714    return tokenize(&snippet, FrontmatterAllowed::No).any(|token| {
2715        matches!(
2716            token.kind,
2717            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
2718        )
2719    });
2720}
2721
2722/// Checks whether a given span has any significant token. A significant token is a non-whitespace
2723/// token, including comments unless `skip_comments` is set.
2724/// This is useful to determine if there are any actual code tokens in the span that are omitted in
2725/// the late pass, such as platform-specific code.
2726pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
2727    matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
2728        match token {
2729            TokenKind::Whitespace => false,
2730            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
2731            _ => true,
2732        }
2733    ))
2734}
2735/// Returns all the comments a given span contains
2736///
2737/// Comments are returned wrapped with their relevant delimiters
2738pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
2739    span_extract_comments(sm, span).join("\n")
2740}
2741
2742/// Returns all the comments a given span contains.
2743///
2744/// Comments are returned wrapped with their relevant delimiters.
2745pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec<String> {
2746    let snippet = sm.span_to_snippet(span).unwrap_or_default();
2747    tokenize_with_text(&snippet)
2748        .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
2749        .map(|(_, s, _)| s.to_string())
2750        .collect::<Vec<_>>()
2751}
2752
2753pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
2754    sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
2755}
2756
2757/// Returns whether the given let pattern and else body can be turned into the `?` operator
2758///
2759/// For this example:
2760/// ```ignore
2761/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None };
2762/// ```
2763/// We get as parameters:
2764/// ```ignore
2765/// pat: Some(a)
2766/// else_body: return None
2767/// ```
2768///
2769/// And for this example:
2770/// ```ignore
2771/// let Some(FooBar { a, b }) = ex else { return None };
2772/// ```
2773/// We get as parameters:
2774/// ```ignore
2775/// pat: Some(FooBar { a, b })
2776/// else_body: return None
2777/// ```
2778///
2779/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
2780/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not.
2781pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
2782    cx: &LateContext<'_>,
2783    pat: &'a Pat<'hir>,
2784    else_body: &Expr<'_>,
2785) -> Option<&'a Pat<'hir>> {
2786    if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind
2787        && cx
2788            .qpath_res(&pat_path, pat.hir_id)
2789            .ctor_parent(cx)
2790            .is_lang_item(cx, OptionSome)
2791        && !is_refutable(cx, inner_pat)
2792        && let else_body = peel_blocks(else_body)
2793        && let ExprKind::Ret(Some(ret_val)) = else_body.kind
2794        && let ExprKind::Path(ret_path) = ret_val.kind
2795        && cx
2796            .qpath_res(&ret_path, ret_val.hir_id)
2797            .ctor_parent(cx)
2798            .is_lang_item(cx, OptionNone)
2799    {
2800        Some(inner_pat)
2801    } else {
2802        None
2803    }
2804}
2805
2806macro_rules! op_utils {
2807    ($($name:ident $assign:ident)*) => {
2808        /// Binary operation traits like `LangItem::Add`
2809        pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
2810
2811        /// Operator-Assign traits like `LangItem::AddAssign`
2812        pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
2813
2814        /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
2815        pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
2816            match kind {
2817                $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
2818                _ => None,
2819            }
2820        }
2821    };
2822}
2823
2824op_utils! {
2825    Add    AddAssign
2826    Sub    SubAssign
2827    Mul    MulAssign
2828    Div    DivAssign
2829    Rem    RemAssign
2830    BitXor BitXorAssign
2831    BitAnd BitAndAssign
2832    BitOr  BitOrAssign
2833    Shl    ShlAssign
2834    Shr    ShrAssign
2835}
2836
2837/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
2838/// that is not locally used.
2839pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool {
2840    match *pat {
2841        PatKind::Wild => true,
2842        PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => {
2843            !visitors::is_local_used(cx, body, id)
2844        },
2845        _ => false,
2846    }
2847}
2848
2849#[derive(Clone, Copy)]
2850pub enum RequiresSemi {
2851    Yes,
2852    No,
2853}
2854impl RequiresSemi {
2855    pub fn requires_semi(self) -> bool {
2856        matches!(self, Self::Yes)
2857    }
2858}
2859
2860/// Check if the expression return `!`, a type coerced from `!`, or could return `!` if the final
2861/// expression were turned into a statement.
2862#[expect(clippy::too_many_lines)]
2863pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<RequiresSemi> {
2864    struct BreakTarget {
2865        id: HirId,
2866        unused: bool,
2867    }
2868
2869    struct V<'cx, 'tcx> {
2870        cx: &'cx LateContext<'tcx>,
2871        break_targets: Vec<BreakTarget>,
2872        break_targets_for_result_ty: u32,
2873        in_final_expr: bool,
2874        requires_semi: bool,
2875        is_never: bool,
2876    }
2877
2878    impl V<'_, '_> {
2879        fn push_break_target(&mut self, id: HirId) {
2880            self.break_targets.push(BreakTarget { id, unused: true });
2881            self.break_targets_for_result_ty += u32::from(self.in_final_expr);
2882        }
2883    }
2884
2885    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
2886        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
2887            // Note: Part of the complexity here comes from the fact that
2888            // coercions are applied to the innermost expression.
2889            // e.g. In `let x: u32 = { break () };` the never-to-any coercion
2890            // is applied to the break expression. This means we can't just
2891            // check the block's type as it will be `u32` despite the fact
2892            // that the block always diverges.
2893
2894            // The rest of the complexity comes from checking blocks which
2895            // syntactically return a value, but will always diverge before
2896            // reaching that point.
2897            // e.g. In `let x = { foo(panic!()) };` the block's type will be the
2898            // return type of `foo` even though it will never actually run. This
2899            // can be trivially fixed by adding a semicolon after the call, but
2900            // we must first detect that a semicolon is needed to make that
2901            // suggestion.
2902
2903            if self.is_never && self.break_targets.is_empty() {
2904                if self.in_final_expr && !self.requires_semi {
2905                    // This expression won't ever run, but we still need to check
2906                    // if it can affect the type of the final expression.
2907                    match e.kind {
2908                        ExprKind::DropTemps(e) => self.visit_expr(e),
2909                        ExprKind::If(_, then, Some(else_)) => {
2910                            self.visit_expr(then);
2911                            self.visit_expr(else_);
2912                        },
2913                        ExprKind::Match(_, arms, _) => {
2914                            for arm in arms {
2915                                self.visit_expr(arm.body);
2916                            }
2917                        },
2918                        ExprKind::Loop(b, ..) => {
2919                            self.push_break_target(e.hir_id);
2920                            self.in_final_expr = false;
2921                            self.visit_block(b);
2922                            self.break_targets.pop();
2923                        },
2924                        ExprKind::Block(b, _) => {
2925                            if b.targeted_by_break {
2926                                self.push_break_target(b.hir_id);
2927                                self.visit_block(b);
2928                                self.break_targets.pop();
2929                            } else {
2930                                self.visit_block(b);
2931                            }
2932                        },
2933                        _ => {
2934                            self.requires_semi = !self.cx.typeck_results().expr_ty(e).is_never();
2935                        },
2936                    }
2937                }
2938                return;
2939            }
2940            match e.kind {
2941                ExprKind::DropTemps(e) => self.visit_expr(e),
2942                ExprKind::Ret(None) | ExprKind::Continue(_) => self.is_never = true,
2943                ExprKind::Ret(Some(e)) | ExprKind::Become(e) => {
2944                    self.in_final_expr = false;
2945                    self.visit_expr(e);
2946                    self.is_never = true;
2947                },
2948                ExprKind::Break(dest, e) => {
2949                    if let Some(e) = e {
2950                        self.in_final_expr = false;
2951                        self.visit_expr(e);
2952                    }
2953                    if let Ok(id) = dest.target_id
2954                        && let Some((i, target)) = self
2955                            .break_targets
2956                            .iter_mut()
2957                            .enumerate()
2958                            .find(|(_, target)| target.id == id)
2959                    {
2960                        target.unused &= self.is_never;
2961                        if i < self.break_targets_for_result_ty as usize {
2962                            self.requires_semi = true;
2963                        }
2964                    }
2965                    self.is_never = true;
2966                },
2967                ExprKind::If(cond, then, else_) => {
2968                    let in_final_expr = mem::replace(&mut self.in_final_expr, false);
2969                    self.visit_expr(cond);
2970                    self.in_final_expr = in_final_expr;
2971
2972                    if self.is_never {
2973                        self.visit_expr(then);
2974                        if let Some(else_) = else_ {
2975                            self.visit_expr(else_);
2976                        }
2977                    } else {
2978                        self.visit_expr(then);
2979                        let is_never = mem::replace(&mut self.is_never, false);
2980                        if let Some(else_) = else_ {
2981                            self.visit_expr(else_);
2982                            self.is_never &= is_never;
2983                        }
2984                    }
2985                },
2986                ExprKind::Match(scrutinee, arms, _) => {
2987                    let in_final_expr = mem::replace(&mut self.in_final_expr, false);
2988                    self.visit_expr(scrutinee);
2989                    self.in_final_expr = in_final_expr;
2990
2991                    if self.is_never {
2992                        for arm in arms {
2993                            self.visit_arm(arm);
2994                        }
2995                    } else {
2996                        let mut is_never = true;
2997                        for arm in arms {
2998                            self.is_never = false;
2999                            if let Some(guard) = arm.guard {
3000                                let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3001                                self.visit_expr(guard);
3002                                self.in_final_expr = in_final_expr;
3003                                // The compiler doesn't consider diverging guards as causing the arm to diverge.
3004                                self.is_never = false;
3005                            }
3006                            self.visit_expr(arm.body);
3007                            is_never &= self.is_never;
3008                        }
3009                        self.is_never = is_never;
3010                    }
3011                },
3012                ExprKind::Loop(b, _, _, _) => {
3013                    self.push_break_target(e.hir_id);
3014                    self.in_final_expr = false;
3015                    self.visit_block(b);
3016                    self.is_never = self.break_targets.pop().unwrap().unused;
3017                },
3018                ExprKind::Block(b, _) => {
3019                    if b.targeted_by_break {
3020                        self.push_break_target(b.hir_id);
3021                        self.visit_block(b);
3022                        self.is_never &= self.break_targets.pop().unwrap().unused;
3023                    } else {
3024                        self.visit_block(b);
3025                    }
3026                },
3027                _ => {
3028                    self.in_final_expr = false;
3029                    walk_expr(self, e);
3030                    self.is_never |= self.cx.typeck_results().expr_ty(e).is_never();
3031                },
3032            }
3033        }
3034
3035        fn visit_block(&mut self, b: &'tcx Block<'_>) {
3036            let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3037            for s in b.stmts {
3038                self.visit_stmt(s);
3039            }
3040            self.in_final_expr = in_final_expr;
3041            if let Some(e) = b.expr {
3042                self.visit_expr(e);
3043            }
3044        }
3045
3046        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
3047            if let Some(e) = l.init {
3048                self.visit_expr(e);
3049            }
3050            if let Some(else_) = l.els {
3051                let is_never = self.is_never;
3052                self.visit_block(else_);
3053                self.is_never = is_never;
3054            }
3055        }
3056
3057        fn visit_arm(&mut self, arm: &Arm<'tcx>) {
3058            if let Some(guard) = arm.guard {
3059                let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3060                self.visit_expr(guard);
3061                self.in_final_expr = in_final_expr;
3062            }
3063            self.visit_expr(arm.body);
3064        }
3065    }
3066
3067    if cx.typeck_results().expr_ty(e).is_never() {
3068        Some(RequiresSemi::No)
3069    } else if let ExprKind::Block(b, _) = e.kind
3070        && !b.targeted_by_break
3071        && b.expr.is_none()
3072    {
3073        // If a block diverges without a final expression then it's type is `!`.
3074        None
3075    } else {
3076        let mut v = V {
3077            cx,
3078            break_targets: Vec::new(),
3079            break_targets_for_result_ty: 0,
3080            in_final_expr: true,
3081            requires_semi: false,
3082            is_never: false,
3083        };
3084        v.visit_expr(e);
3085        v.is_never
3086            .then_some(if v.requires_semi && matches!(e.kind, ExprKind::Block(..)) {
3087                RequiresSemi::Yes
3088            } else {
3089                RequiresSemi::No
3090            })
3091    }
3092}
3093
3094/// Produces a path from a local caller to the type of the called method. Suitable for user
3095/// output/suggestions.
3096///
3097/// Returned path can be either absolute (for methods defined non-locally), or relative (for local
3098/// methods).
3099pub fn get_path_from_caller_to_method_type<'tcx>(
3100    tcx: TyCtxt<'tcx>,
3101    from: LocalDefId,
3102    method: DefId,
3103    args: GenericArgsRef<'tcx>,
3104) -> String {
3105    let assoc_item = tcx.associated_item(method);
3106    let def_id = assoc_item.container_id(tcx);
3107    match assoc_item.container {
3108        rustc_ty::AssocContainer::Trait => get_path_to_callee(tcx, from, def_id),
3109        rustc_ty::AssocContainer::InherentImpl | rustc_ty::AssocContainer::TraitImpl(_) => {
3110            let ty = tcx.type_of(def_id).instantiate_identity();
3111            get_path_to_ty(tcx, from, ty, args)
3112        },
3113    }
3114}
3115
3116fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args: GenericArgsRef<'tcx>) -> String {
3117    match ty.kind() {
3118        rustc_ty::Adt(adt, _) => get_path_to_callee(tcx, from, adt.did()),
3119        // TODO these types need to be recursively resolved as well
3120        rustc_ty::Array(..)
3121        | rustc_ty::Dynamic(..)
3122        | rustc_ty::Never
3123        | rustc_ty::RawPtr(_, _)
3124        | rustc_ty::Ref(..)
3125        | rustc_ty::Slice(_)
3126        | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)),
3127        _ => ty.to_string(),
3128    }
3129}
3130
3131/// Produce a path from some local caller to the callee. Suitable for user output/suggestions.
3132fn get_path_to_callee(tcx: TyCtxt<'_>, from: LocalDefId, callee: DefId) -> String {
3133    // only search for a relative path if the call is fully local
3134    if callee.is_local() {
3135        let callee_path = tcx.def_path(callee);
3136        let caller_path = tcx.def_path(from.to_def_id());
3137        maybe_get_relative_path(&caller_path, &callee_path, 2)
3138    } else {
3139        tcx.def_path_str(callee)
3140    }
3141}
3142
3143/// Tries to produce a relative path from `from` to `to`; if such a path would contain more than
3144/// `max_super` `super` items, produces an absolute path instead. Both `from` and `to` should be in
3145/// the local crate.
3146///
3147/// Suitable for user output/suggestions.
3148///
3149/// This ignores use items, and assumes that the target path is visible from the source
3150/// path (which _should_ be a reasonable assumption since we in order to be able to use an object of
3151/// certain type T, T is required to be visible).
3152///
3153/// TODO make use of `use` items. Maybe we should have something more sophisticated like
3154/// rust-analyzer does? <https://docs.rs/ra_ap_hir_def/0.0.169/src/ra_ap_hir_def/find_path.rs.html#19-27>
3155fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> String {
3156    use itertools::EitherOrBoth::{Both, Left, Right};
3157
3158    // 1. skip the segments common for both paths (regardless of their type)
3159    let unique_parts = to
3160        .data
3161        .iter()
3162        .zip_longest(from.data.iter())
3163        .skip_while(|el| matches!(el, Both(l, r) if l == r))
3164        .map(|el| match el {
3165            Both(l, r) => Both(l.data, r.data),
3166            Left(l) => Left(l.data),
3167            Right(r) => Right(r.data),
3168        });
3169
3170    // 2. for the remaining segments, construct relative path using only mod names and `super`
3171    let mut go_up_by = 0;
3172    let mut path = Vec::new();
3173    for el in unique_parts {
3174        match el {
3175            Both(l, r) => {
3176                // consider:
3177                // a::b::sym:: ::    refers to
3178                // c::d::e  ::f::sym
3179                // result should be super::super::c::d::e::f
3180                //
3181                // alternatively:
3182                // a::b::c  ::d::sym refers to
3183                // e::f::sym:: ::
3184                // result should be super::super::super::super::e::f
3185                if let DefPathData::TypeNs(sym) = l {
3186                    path.push(sym);
3187                }
3188                if let DefPathData::TypeNs(_) = r {
3189                    go_up_by += 1;
3190                }
3191            },
3192            // consider:
3193            // a::b::sym:: ::    refers to
3194            // c::d::e  ::f::sym
3195            // when looking at `f`
3196            Left(DefPathData::TypeNs(sym)) => path.push(sym),
3197            // consider:
3198            // a::b::c  ::d::sym refers to
3199            // e::f::sym:: ::
3200            // when looking at `d`
3201            Right(DefPathData::TypeNs(_)) => go_up_by += 1,
3202            _ => {},
3203        }
3204    }
3205
3206    if go_up_by > max_super {
3207        // `super` chain would be too long, just use the absolute path instead
3208        join_path_syms(once(kw::Crate).chain(to.data.iter().filter_map(|el| {
3209            if let DefPathData::TypeNs(sym) = el.data {
3210                Some(sym)
3211            } else {
3212                None
3213            }
3214        })))
3215    } else {
3216        join_path_syms(repeat_n(kw::Super, go_up_by).chain(path))
3217    }
3218}
3219
3220/// Returns true if the specified `HirId` is the top-level expression of a statement or the only
3221/// expression in a block.
3222pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
3223    matches!(
3224        cx.tcx.parent_hir_node(id),
3225        Node::Stmt(..) | Node::Block(Block { stmts: [], .. })
3226    )
3227}
3228
3229/// Returns true if the given `expr` is a block or resembled as a block,
3230/// such as `if`, `loop`, `match` expressions etc.
3231pub fn is_block_like(expr: &Expr<'_>) -> bool {
3232    matches!(
3233        expr.kind,
3234        ExprKind::Block(..) | ExprKind::ConstBlock(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..)
3235    )
3236}
3237
3238/// Returns true if the given `expr` is binary expression that needs to be wrapped in parentheses.
3239pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool {
3240    fn contains_block(expr: &Expr<'_>, is_operand: bool) -> bool {
3241        match expr.kind {
3242            ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => contains_block(lhs, true),
3243            _ if is_block_like(expr) => is_operand,
3244            _ => false,
3245        }
3246    }
3247
3248    contains_block(expr, false)
3249}
3250
3251/// Returns true if the specified expression is in a receiver position.
3252pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3253    if let Some(parent_expr) = get_parent_expr(cx, expr)
3254        && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind
3255        && receiver.hir_id == expr.hir_id
3256    {
3257        return true;
3258    }
3259    false
3260}
3261
3262/// Returns true if `expr` creates any temporary whose type references a non-static lifetime and has
3263/// a significant drop and does not consume it.
3264pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
3265    for_each_unconsumed_temporary(cx, expr, |temporary_ty| {
3266        if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env())
3267            && temporary_ty
3268                .walk()
3269                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
3270        {
3271            ControlFlow::Break(())
3272        } else {
3273            ControlFlow::Continue(())
3274        }
3275    })
3276    .is_break()
3277}
3278
3279/// Returns true if the specified `expr` requires coercion,
3280/// meaning that it either has a coercion or propagates a coercion from one of its sub expressions.
3281///
3282/// Similar to [`is_adjusted`], this not only checks if an expression's type was adjusted,
3283/// but also going through extra steps to see if it fits the description of [coercion sites].
3284///
3285/// You should used this when you want to avoid suggesting replacing an expression that is currently
3286/// a coercion site or coercion propagating expression with one that is not.
3287///
3288/// [coercion sites]: https://doc.rust-lang.org/stable/reference/type-coercions.html#coercion-sites
3289pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
3290    let expr_ty_is_adjusted = cx
3291        .typeck_results()
3292        .expr_adjustments(expr)
3293        .iter()
3294        // ignore `NeverToAny` adjustments, such as `panic!` call.
3295        .any(|adj| !matches!(adj.kind, Adjust::NeverToAny));
3296    if expr_ty_is_adjusted {
3297        return true;
3298    }
3299
3300    // Identify coercion sites and recursively check if those sites
3301    // actually have type adjustments.
3302    match expr.kind {
3303        ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => {
3304            let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
3305
3306            if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) {
3307                return false;
3308            }
3309
3310            let self_arg_count = usize::from(matches!(expr.kind, ExprKind::MethodCall(..)));
3311            let mut args_with_ty_param = {
3312                fn_sig
3313                    .inputs()
3314                    .skip_binder()
3315                    .iter()
3316                    .skip(self_arg_count)
3317                    .zip(args)
3318                    .filter_map(|(arg_ty, arg)| {
3319                        if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) {
3320                            Some(arg)
3321                        } else {
3322                            None
3323                        }
3324                    })
3325            };
3326            args_with_ty_param.any(|arg| expr_requires_coercion(cx, arg))
3327        },
3328        // Struct/union initialization.
3329        ExprKind::Struct(qpath, _, _) => {
3330            let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
3331            if let Some((_, v_def)) = adt_and_variant_of_res(cx, res) {
3332                let rustc_ty::Adt(_, generic_args) = cx.typeck_results().expr_ty_adjusted(expr).kind() else {
3333                    // This should never happen, but when it does, not linting is the better option.
3334                    return true;
3335                };
3336                v_def
3337                    .fields
3338                    .iter()
3339                    .any(|field| field.ty(cx.tcx, generic_args).has_type_flags(TypeFlags::HAS_TY_PARAM))
3340            } else {
3341                false
3342            }
3343        },
3344        // Function results, including the final line of a block or a `return` expression.
3345        ExprKind::Block(
3346            &Block {
3347                expr: Some(ret_expr), ..
3348            },
3349            _,
3350        )
3351        | ExprKind::Ret(Some(ret_expr)) => expr_requires_coercion(cx, ret_expr),
3352
3353        // ===== Coercion-propagation expressions =====
3354        ExprKind::Array(elems) | ExprKind::Tup(elems) => elems.iter().any(|elem| expr_requires_coercion(cx, elem)),
3355        // Array but with repeating syntax.
3356        ExprKind::Repeat(rep_elem, _) => expr_requires_coercion(cx, rep_elem),
3357        // Others that may contain coercion sites.
3358        ExprKind::If(_, then, maybe_else) => {
3359            expr_requires_coercion(cx, then) || maybe_else.is_some_and(|e| expr_requires_coercion(cx, e))
3360        },
3361        ExprKind::Match(_, arms, _) => arms
3362            .iter()
3363            .map(|arm| arm.body)
3364            .any(|body| expr_requires_coercion(cx, body)),
3365        _ => false,
3366    }
3367}
3368
3369/// Returns `true` if `expr` designates a mutable static, a mutable local binding, or an expression
3370/// that can be owned.
3371pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3372    if let Some(hir_id) = expr.res_local_id()
3373        && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
3374    {
3375        matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
3376    } else if let ExprKind::Path(p) = &expr.kind
3377        && let Some(mutability) = cx
3378            .qpath_res(p, expr.hir_id)
3379            .opt_def_id()
3380            .and_then(|id| cx.tcx.static_mutability(id))
3381    {
3382        mutability == Mutability::Mut
3383    } else if let ExprKind::Field(parent, _) = expr.kind {
3384        is_mutable(cx, parent)
3385    } else {
3386        true
3387    }
3388}
3389
3390/// Peel `Option<…>` from `hir_ty` as long as the HIR name is `Option` and it corresponds to the
3391/// `core::Option<_>` type.
3392pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
3393    let Some(option_def_id) = cx.tcx.get_diagnostic_item(sym::Option) else {
3394        return hir_ty;
3395    };
3396    while let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind
3397        && let Some(segment) = path.segments.last()
3398        && segment.ident.name == sym::Option
3399        && let Res::Def(DefKind::Enum, def_id) = segment.res
3400        && def_id == option_def_id
3401        && let [GenericArg::Type(arg_ty)] = segment.args().args
3402    {
3403        hir_ty = arg_ty.as_unambig_ty();
3404    }
3405    hir_ty
3406}
3407
3408/// If `expr` is a desugared `.await`, return the original expression if it does not come from a
3409/// macro expansion.
3410pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
3411    if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind
3412        && let ExprKind::Call(_, [into_future_arg]) = match_value.kind
3413        && let ctxt = expr.span.ctxt()
3414        && for_each_expr_without_closures(into_future_arg, |e| {
3415            walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))
3416        })
3417        .is_none()
3418    {
3419        Some(into_future_arg)
3420    } else {
3421        None
3422    }
3423}
3424
3425/// Checks if the given expression is a call to `Default::default()`.
3426pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
3427    if let ExprKind::Call(fn_expr, []) = &expr.kind
3428        && let ExprKind::Path(qpath) = &fn_expr.kind
3429        && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
3430    {
3431        cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
3432    } else {
3433        false
3434    }
3435}
3436
3437/// Checks if `expr` may be directly used as the return value of its enclosing body.
3438/// The following cases are covered:
3439/// - `expr` as the last expression of the body, or of a block that can be used as the return value
3440/// - `return expr`
3441/// - then or else part of a `if` in return position
3442/// - arm body of a `match` in a return position
3443/// - `break expr` or `break 'label expr` if the loop or block being exited is used as a return
3444///   value
3445///
3446/// Contrary to [`TyCtxt::hir_get_fn_id_for_return_block()`], if `expr` is part of a
3447/// larger expression, for example a field expression of a `struct`, it will not be
3448/// considered as matching the condition and will return `false`.
3449///
3450/// Also, even if `expr` is assigned to a variable which is later returned, this function
3451/// will still return `false` because `expr` is not used *directly* as the return value
3452/// as it goes through the intermediate variable.
3453pub fn potential_return_of_enclosing_body(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3454    let enclosing_body_owner = cx
3455        .tcx
3456        .local_def_id_to_hir_id(cx.tcx.hir_enclosing_body_owner(expr.hir_id));
3457    let mut prev_id = expr.hir_id;
3458    let mut skip_until_id = None;
3459    for (hir_id, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
3460        if hir_id == enclosing_body_owner {
3461            return true;
3462        }
3463        if let Some(id) = skip_until_id {
3464            prev_id = hir_id;
3465            if id == hir_id {
3466                skip_until_id = None;
3467            }
3468            continue;
3469        }
3470        match node {
3471            Node::Block(Block { expr, .. }) if expr.is_some_and(|expr| expr.hir_id == prev_id) => {},
3472            Node::Arm(arm) if arm.body.hir_id == prev_id => {},
3473            Node::Expr(expr) => match expr.kind {
3474                ExprKind::Ret(_) => return true,
3475                ExprKind::If(_, then, opt_else)
3476                    if then.hir_id == prev_id || opt_else.is_some_and(|els| els.hir_id == prev_id) => {},
3477                ExprKind::Match(_, arms, _) if arms.iter().any(|arm| arm.hir_id == prev_id) => {},
3478                ExprKind::Block(block, _) if block.hir_id == prev_id => {},
3479                ExprKind::Break(
3480                    Destination {
3481                        target_id: Ok(target_id),
3482                        ..
3483                    },
3484                    _,
3485                ) => skip_until_id = Some(target_id),
3486                _ => break,
3487            },
3488            _ => break,
3489        }
3490        prev_id = hir_id;
3491    }
3492
3493    // `expr` is used as part of "something" and is not returned directly from its
3494    // enclosing body.
3495    false
3496}
3497
3498/// Checks if the expression has adjustments that require coercion, for example: dereferencing with
3499/// overloaded deref, coercing pointers and `dyn` objects.
3500pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3501    cx.typeck_results().expr_adjustments(expr).iter().any(|adj| {
3502        matches!(
3503            adj.kind,
3504            Adjust::Deref(Some(_)) | Adjust::Pointer(PointerCoercion::Unsize) | Adjust::NeverToAny
3505        )
3506    })
3507}
3508
3509/// Checks if the expression is an async block (i.e., `async { ... }`).
3510pub fn is_expr_async_block(expr: &Expr<'_>) -> bool {
3511    matches!(
3512        expr.kind,
3513        ExprKind::Closure(Closure {
3514            kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(
3515                CoroutineDesugaring::Async,
3516                CoroutineSource::Block
3517            )),
3518            ..
3519        })
3520    )
3521}
3522
3523/// Checks if the chosen edition and `msrv` allows using `if let` chains.
3524pub fn can_use_if_let_chains(cx: &LateContext<'_>, msrv: Msrv) -> bool {
3525    cx.tcx.sess.edition().at_least_rust_2024() && msrv.meets(cx, msrvs::LET_CHAINS)
3526}