Skip to main content

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