clippy_utils/
lib.rs

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