Skip to main content

clippy_utils/
lib.rs

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