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