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