Skip to main content

clippy_utils/
lib.rs

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