clippy_utils/
lib.rs

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