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_parsing;
32extern crate rustc_const_eval;
33extern crate rustc_data_structures;
34// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate.
35#[allow(unused_extern_crates)]
36extern crate rustc_driver;
37extern crate rustc_errors;
38extern crate rustc_hir;
39extern crate rustc_hir_analysis;
40extern crate rustc_hir_typeck;
41extern crate rustc_index;
42extern crate rustc_infer;
43extern crate rustc_lexer;
44extern crate rustc_lint;
45extern crate rustc_middle;
46extern crate rustc_mir_dataflow;
47extern crate rustc_session;
48extern crate rustc_span;
49extern crate rustc_trait_selection;
50extern crate smallvec;
51
52pub mod ast_utils;
53pub mod attrs;
54mod check_proc_macro;
55pub mod comparisons;
56pub mod consts;
57pub mod diagnostics;
58pub mod eager_or_lazy;
59pub mod higher;
60mod hir_utils;
61pub mod macros;
62pub mod mir;
63pub mod msrvs;
64pub mod numeric_literal;
65pub mod paths;
66pub mod ptr;
67pub mod qualify_min_const_fn;
68pub mod source;
69pub mod str_utils;
70pub mod sugg;
71pub mod sym;
72pub mod ty;
73pub mod usage;
74pub mod visitors;
75
76pub use self::attrs::*;
77pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
78pub use self::hir_utils::{
79    HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, has_ambiguous_literal_in_expr, hash_expr,
80    hash_stmt, is_bool, over,
81};
82
83use core::mem;
84use core::ops::ControlFlow;
85use std::collections::hash_map::Entry;
86use std::iter::{once, repeat_n};
87use std::sync::{Mutex, MutexGuard, OnceLock};
88
89use itertools::Itertools;
90use rustc_abi::Integer;
91use rustc_ast::ast::{self, LitKind, RangeLimits};
92use rustc_ast::join_path_syms;
93use rustc_hir::attrs::{AttributeKind};
94use rustc_hir::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, PointerCoercion};
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_assoc(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_assoc(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_assoc(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_assoc(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/// * `|[x, y]| [x, y]`
1901///
1902/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
1903fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
1904    fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
1905        if cx
1906            .typeck_results()
1907            .pat_binding_modes()
1908            .get(pat.hir_id)
1909            .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
1910        {
1911            // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
1912            // due to match ergonomics, the inner patterns become references. Don't consider this
1913            // the identity function as that changes types.
1914            return false;
1915        }
1916
1917        match (pat.kind, expr.kind) {
1918            (PatKind::Binding(_, id, _, _), _) => {
1919                path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()
1920            },
1921            (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup))
1922                if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() =>
1923            {
1924                pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr))
1925            },
1926            (PatKind::Slice(before, slice, after), ExprKind::Array(arr))
1927                if slice.is_none() && before.len() + after.len() == arr.len() =>
1928            {
1929                (before.iter().chain(after))
1930                    .zip(arr)
1931                    .all(|(pat, expr)| check_pat(cx, pat, expr))
1932            },
1933            _ => false,
1934        }
1935    }
1936
1937    let [param] = func.params else {
1938        return false;
1939    };
1940
1941    let mut expr = func.value;
1942    loop {
1943        match expr.kind {
1944            ExprKind::Block(
1945                &Block {
1946                    stmts: [],
1947                    expr: Some(e),
1948                    ..
1949                },
1950                _,
1951            )
1952            | ExprKind::Ret(Some(e)) => expr = e,
1953            ExprKind::Block(
1954                &Block {
1955                    stmts: [stmt],
1956                    expr: None,
1957                    ..
1958                },
1959                _,
1960            ) => {
1961                if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind
1962                    && let ExprKind::Ret(Some(ret_val)) = e.kind
1963                {
1964                    expr = ret_val;
1965                } else {
1966                    return false;
1967                }
1968            },
1969            _ => return check_pat(cx, param.pat, expr),
1970        }
1971    }
1972}
1973
1974/// This is the same as [`is_expr_identity_function`], but does not consider closures
1975/// with type annotations for its bindings (or similar) as identity functions:
1976/// * `|x: u8| x`
1977/// * `std::convert::identity::<u8>`
1978pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1979    match expr.kind {
1980        ExprKind::Closure(&Closure { body, fn_decl, .. })
1981            if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) =>
1982        {
1983            is_body_identity_function(cx, cx.tcx.hir_body(body))
1984        },
1985        ExprKind::Path(QPath::Resolved(_, path))
1986            if path.segments.iter().all(|seg| seg.infer_args)
1987                && let Some(did) = path.res.opt_def_id() =>
1988        {
1989            cx.tcx.is_diagnostic_item(sym::convert_identity, did)
1990        },
1991        _ => false,
1992    }
1993}
1994
1995/// Checks if an expression represents the identity function
1996/// Only examines closures and `std::convert::identity`
1997///
1998/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want
1999/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't
2000/// have type annotations. This is important because removing a closure with bindings can
2001/// remove type information that helped type inference before, which can then lead to compile
2002/// errors.
2003pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
2004    match expr.kind {
2005        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir_body(body)),
2006        _ => path_def_id(cx, expr).is_some_and(|id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
2007    }
2008}
2009
2010/// Gets the node where an expression is either used, or it's type is unified with another branch.
2011/// Returns both the node and the `HirId` of the closest child node.
2012pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
2013    let mut child_id = expr.hir_id;
2014    let mut iter = tcx.hir_parent_iter(child_id);
2015    loop {
2016        match iter.next() {
2017            None => break None,
2018            Some((id, Node::Block(_))) => child_id = id,
2019            Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
2020            Some((_, Node::Expr(expr))) => match expr.kind {
2021                ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
2022                ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
2023                ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
2024                _ => break Some((Node::Expr(expr), child_id)),
2025            },
2026            Some((_, node)) => break Some((node, child_id)),
2027        }
2028    }
2029}
2030
2031/// Checks if the result of an expression is used, or it's type is unified with another branch.
2032pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
2033    !matches!(
2034        get_expr_use_or_unification_node(tcx, expr),
2035        None | Some((
2036            Node::Stmt(Stmt {
2037                kind: StmtKind::Expr(_)
2038                    | StmtKind::Semi(_)
2039                    | StmtKind::Let(LetStmt {
2040                        pat: Pat {
2041                            kind: PatKind::Wild,
2042                            ..
2043                        },
2044                        ..
2045                    }),
2046                ..
2047            }),
2048            _
2049        ))
2050    )
2051}
2052
2053/// Checks if the expression is the final expression returned from a block.
2054pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
2055    matches!(tcx.parent_hir_node(expr.hir_id), Node::Block(..))
2056}
2057
2058/// Checks if the expression is a temporary value.
2059// This logic is the same as the one used in rustc's `check_named_place_expr function`.
2060// https://github.com/rust-lang/rust/blob/3ed2a10d173d6c2e0232776af338ca7d080b1cd4/compiler/rustc_hir_typeck/src/expr.rs#L482-L499
2061pub fn is_expr_temporary_value(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
2062    !expr.is_place_expr(|base| {
2063        cx.typeck_results()
2064            .adjustments()
2065            .get(base.hir_id)
2066            .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
2067    })
2068}
2069
2070pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
2071    if !is_no_std_crate(cx) {
2072        Some("std")
2073    } else if !is_no_core_crate(cx) {
2074        Some("core")
2075    } else {
2076        None
2077    }
2078}
2079
2080pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
2081    cx.tcx
2082        .hir_attrs(hir::CRATE_HIR_ID)
2083        .iter()
2084        .any(|attr| attr.has_name(sym::no_std))
2085}
2086
2087pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
2088    cx.tcx
2089        .hir_attrs(hir::CRATE_HIR_ID)
2090        .iter()
2091        .any(|attr| attr.has_name(sym::no_core))
2092}
2093
2094/// Check if parent of a hir node is a trait implementation block.
2095/// For example, `f` in
2096/// ```no_run
2097/// # struct S;
2098/// # trait Trait { fn f(); }
2099/// impl Trait for S {
2100///     fn f() {}
2101/// }
2102/// ```
2103pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
2104    if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
2105        matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }))
2106    } else {
2107        false
2108    }
2109}
2110
2111/// Check if it's even possible to satisfy the `where` clause for the item.
2112///
2113/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
2114///
2115/// ```ignore
2116/// fn foo() where i32: Iterator {
2117///     for _ in 2i32 {}
2118/// }
2119/// ```
2120pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
2121    use rustc_trait_selection::traits;
2122    let predicates = cx
2123        .tcx
2124        .predicates_of(did)
2125        .predicates
2126        .iter()
2127        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
2128    traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
2129}
2130
2131/// Returns the `DefId` of the callee if the given expression is a function or method call.
2132pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
2133    fn_def_id_with_node_args(cx, expr).map(|(did, _)| did)
2134}
2135
2136/// Returns the `DefId` of the callee if the given expression is a function or method call,
2137/// as well as its node args.
2138pub fn fn_def_id_with_node_args<'tcx>(
2139    cx: &LateContext<'tcx>,
2140    expr: &Expr<'_>,
2141) -> Option<(DefId, GenericArgsRef<'tcx>)> {
2142    let typeck = cx.typeck_results();
2143    match &expr.kind {
2144        ExprKind::MethodCall(..) => Some((
2145            typeck.type_dependent_def_id(expr.hir_id)?,
2146            typeck.node_args(expr.hir_id),
2147        )),
2148        ExprKind::Call(
2149            Expr {
2150                kind: ExprKind::Path(qpath),
2151                hir_id: path_hir_id,
2152                ..
2153            },
2154            ..,
2155        ) => {
2156            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
2157            // deref to fn pointers, dyn Fn, impl Fn - #8850
2158            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
2159                typeck.qpath_res(qpath, *path_hir_id)
2160            {
2161                Some((id, typeck.node_args(*path_hir_id)))
2162            } else {
2163                None
2164            }
2165        },
2166        _ => None,
2167    }
2168}
2169
2170/// Returns `Option<String>` where String is a textual representation of the type encapsulated in
2171/// the slice iff the given expression is a slice of primitives.
2172///
2173/// (As defined in the `is_recursively_primitive_type` function.) Returns `None` otherwise.
2174pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
2175    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
2176    let expr_kind = expr_type.kind();
2177    let is_primitive = match expr_kind {
2178        rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type),
2179        rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
2180            if let rustc_ty::Slice(element_type) = inner_ty.kind() {
2181                is_recursively_primitive_type(*element_type)
2182            } else {
2183                unreachable!()
2184            }
2185        },
2186        _ => false,
2187    };
2188
2189    if is_primitive {
2190        // if we have wrappers like Array, Slice or Tuple, print these
2191        // and get the type enclosed in the slice ref
2192        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
2193            rustc_ty::Slice(..) => return Some("slice".into()),
2194            rustc_ty::Array(..) => return Some("array".into()),
2195            rustc_ty::Tuple(..) => return Some("tuple".into()),
2196            _ => {
2197                // is_recursively_primitive_type() should have taken care
2198                // of the rest and we can rely on the type that is found
2199                let refs_peeled = expr_type.peel_refs();
2200                return Some(refs_peeled.walk().last().unwrap().to_string());
2201            },
2202        }
2203    }
2204    None
2205}
2206
2207/// Returns a list of groups where elements in each group are equal according to `eq`
2208///
2209/// - Within each group the elements are sorted by the order they appear in `exprs`
2210/// - The groups themselves are sorted by their first element's appearence in `exprs`
2211///
2212/// Given functions `eq` and `hash` such that `eq(a, b) == true`
2213/// implies `hash(a) == hash(b)`
2214pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<Vec<&T>>
2215where
2216    Hash: FnMut(&T) -> u64,
2217    Eq: FnMut(&T, &T) -> bool,
2218{
2219    match exprs {
2220        [a, b] if eq(a, b) => return vec![vec![a, b]],
2221        _ if exprs.len() <= 2 => return vec![],
2222        _ => {},
2223    }
2224
2225    let mut buckets: UnindexMap<u64, Vec<Vec<&T>>> = UnindexMap::default();
2226
2227    for expr in exprs {
2228        match buckets.entry(hash(expr)) {
2229            indexmap::map::Entry::Occupied(mut o) => {
2230                let bucket = o.get_mut();
2231                match bucket.iter_mut().find(|group| eq(expr, group[0])) {
2232                    Some(group) => group.push(expr),
2233                    None => bucket.push(vec![expr]),
2234                }
2235            },
2236            indexmap::map::Entry::Vacant(v) => {
2237                v.insert(vec![vec![expr]]);
2238            },
2239        }
2240    }
2241
2242    buckets
2243        .into_values()
2244        .flatten()
2245        .filter(|group| group.len() > 1)
2246        .collect()
2247}
2248
2249/// Peels off all references on the pattern. Returns the underlying pattern and the number of
2250/// references removed.
2251pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
2252    fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
2253        if let PatKind::Ref(pat, _) = pat.kind {
2254            peel(pat, count + 1)
2255        } else {
2256            (pat, count)
2257        }
2258    }
2259    peel(pat, 0)
2260}
2261
2262/// Peels of expressions while the given closure returns `Some`.
2263pub fn peel_hir_expr_while<'tcx>(
2264    mut expr: &'tcx Expr<'tcx>,
2265    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
2266) -> &'tcx Expr<'tcx> {
2267    while let Some(e) = f(expr) {
2268        expr = e;
2269    }
2270    expr
2271}
2272
2273/// Peels off up to the given number of references on the expression. Returns the underlying
2274/// expression and the number of references removed.
2275pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
2276    let mut remaining = count;
2277    let e = peel_hir_expr_while(expr, |e| match e.kind {
2278        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
2279            remaining -= 1;
2280            Some(e)
2281        },
2282        _ => None,
2283    });
2284    (e, count - remaining)
2285}
2286
2287/// Peels off all unary operators of an expression. Returns the underlying expression and the number
2288/// of operators removed.
2289pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2290    let mut count: usize = 0;
2291    let mut curr_expr = expr;
2292    while let ExprKind::Unary(_, local_expr) = curr_expr.kind {
2293        count = count.wrapping_add(1);
2294        curr_expr = local_expr;
2295    }
2296    (curr_expr, count)
2297}
2298
2299/// Peels off all references on the expression. Returns the underlying expression and the number of
2300/// references removed.
2301pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2302    let mut count = 0;
2303    let e = peel_hir_expr_while(expr, |e| match e.kind {
2304        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
2305            count += 1;
2306            Some(e)
2307        },
2308        _ => None,
2309    });
2310    (e, count)
2311}
2312
2313/// Peels off all references on the type. Returns the underlying type and the number of references
2314/// removed.
2315pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) {
2316    let mut count = 0;
2317    loop {
2318        match &ty.kind {
2319            TyKind::Ref(_, ref_ty) => {
2320                ty = ref_ty.ty;
2321                count += 1;
2322            },
2323            _ => break (ty, count),
2324        }
2325    }
2326}
2327
2328/// Peels off all references on the type. Returns the underlying type and the number of references
2329/// removed.
2330pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
2331    let mut count = 0;
2332    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
2333        ty = *dest_ty;
2334        count += 1;
2335    }
2336    (ty, count)
2337}
2338
2339/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
2340/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
2341pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
2342    loop {
2343        match expr.kind {
2344            ExprKind::AddrOf(_, _, e) => expr = e,
2345            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
2346            _ => break,
2347        }
2348    }
2349    expr
2350}
2351
2352pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
2353    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
2354        && let Res::Def(_, def_id) = path.res
2355    {
2356        return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
2357    }
2358    false
2359}
2360
2361static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalModDefId, Vec<Symbol>>>> = OnceLock::new();
2362
2363/// Apply `f()` to the set of test item names.
2364/// The names are sorted using the default `Symbol` ordering.
2365fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&[Symbol]) -> bool) -> bool {
2366    let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
2367    let mut map: MutexGuard<'_, FxHashMap<LocalModDefId, Vec<Symbol>>> = cache.lock().unwrap();
2368    let value = map.entry(module);
2369    match value {
2370        Entry::Occupied(entry) => f(entry.get()),
2371        Entry::Vacant(entry) => {
2372            let mut names = Vec::new();
2373            for id in tcx.hir_module_free_items(module) {
2374                if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
2375                    && let item = tcx.hir_item(id)
2376                    && let ItemKind::Const(ident, _generics, ty, _body) = item.kind
2377                    && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
2378                        // We could also check for the type name `test::TestDescAndFn`
2379                        && let Res::Def(DefKind::Struct, _) = path.res
2380                {
2381                    let has_test_marker = tcx
2382                        .hir_attrs(item.hir_id())
2383                        .iter()
2384                        .any(|a| a.has_name(sym::rustc_test_marker));
2385                    if has_test_marker {
2386                        names.push(ident.name);
2387                    }
2388                }
2389            }
2390            names.sort_unstable();
2391            f(entry.insert(names))
2392        },
2393    }
2394}
2395
2396/// Checks if the function containing the given `HirId` is a `#[test]` function
2397///
2398/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
2399pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
2400    with_test_item_names(tcx, tcx.parent_module(id), |names| {
2401        let node = tcx.hir_node(id);
2402        once((id, node))
2403            .chain(tcx.hir_parent_iter(id))
2404            // Since you can nest functions we need to collect all until we leave
2405            // function scope
2406            .any(|(_id, node)| {
2407                if let Node::Item(item) = node
2408                    && let ItemKind::Fn { ident, .. } = item.kind
2409                {
2410                    // Note that we have sorted the item names in the visitor,
2411                    // so the binary_search gets the same as `contains`, but faster.
2412                    return names.binary_search(&ident.name).is_ok();
2413                }
2414                false
2415            })
2416    })
2417}
2418
2419/// Checks if `fn_def_id` has a `#[test]` attribute applied
2420///
2421/// This only checks directly applied attributes. To see if a node has a parent function marked with
2422/// `#[test]` use [`is_in_test_function`].
2423///
2424/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
2425pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool {
2426    let id = tcx.local_def_id_to_hir_id(fn_def_id);
2427    if let Node::Item(item) = tcx.hir_node(id)
2428        && let ItemKind::Fn { ident, .. } = item.kind
2429    {
2430        with_test_item_names(tcx, tcx.parent_module(id), |names| {
2431            names.binary_search(&ident.name).is_ok()
2432        })
2433    } else {
2434        false
2435    }
2436}
2437
2438/// Checks if `id` has a `#[cfg(test)]` attribute applied
2439///
2440/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
2441/// use [`is_in_cfg_test`]
2442pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
2443    tcx.hir_attrs(id).iter().any(|attr| {
2444        if attr.has_name(sym::cfg_trace)
2445            && let Some(items) = attr.meta_item_list()
2446            && let [item] = &*items
2447            && item.has_name(sym::test)
2448        {
2449            true
2450        } else {
2451            false
2452        }
2453    })
2454}
2455
2456/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
2457pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
2458    tcx.hir_parent_id_iter(id).any(|parent_id| is_cfg_test(tcx, parent_id))
2459}
2460
2461/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]`
2462pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
2463    is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id)
2464}
2465
2466/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
2467pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
2468    tcx.has_attr(def_id, sym::cfg_trace)
2469        || tcx
2470            .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
2471            .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id))
2472            .any(|attr| attr.has_name(sym::cfg_trace))
2473}
2474
2475/// Walks up the HIR tree from the given expression in an attempt to find where the value is
2476/// consumed.
2477///
2478/// Termination has three conditions:
2479/// - The given function returns `Break`. This function will return the value.
2480/// - The consuming node is found. This function will return `Continue(use_node, child_id)`.
2481/// - No further parent nodes are found. This will trigger a debug assert or return `None`.
2482///
2483/// This allows walking through `if`, `match`, `break`, and block expressions to find where the
2484/// value produced by the expression is consumed.
2485pub fn walk_to_expr_usage<'tcx, T>(
2486    cx: &LateContext<'tcx>,
2487    e: &Expr<'tcx>,
2488    mut f: impl FnMut(HirId, Node<'tcx>, HirId) -> ControlFlow<T>,
2489) -> Option<ControlFlow<T, (Node<'tcx>, HirId)>> {
2490    let mut iter = cx.tcx.hir_parent_iter(e.hir_id);
2491    let mut child_id = e.hir_id;
2492
2493    while let Some((parent_id, parent)) = iter.next() {
2494        if let ControlFlow::Break(x) = f(parent_id, parent, child_id) {
2495            return Some(ControlFlow::Break(x));
2496        }
2497        let parent_expr = match parent {
2498            Node::Expr(e) => e,
2499            Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
2500                child_id = parent_id;
2501                continue;
2502            },
2503            Node::Arm(a) if a.body.hir_id == child_id => {
2504                child_id = parent_id;
2505                continue;
2506            },
2507            _ => return Some(ControlFlow::Continue((parent, child_id))),
2508        };
2509        match parent_expr.kind {
2510            ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
2511            ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
2512                child_id = id;
2513                iter = cx.tcx.hir_parent_iter(id);
2514            },
2515            ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = parent_id,
2516            _ => return Some(ControlFlow::Continue((parent, child_id))),
2517        }
2518    }
2519    debug_assert!(false, "no parent node found for `{child_id:?}`");
2520    None
2521}
2522
2523/// A type definition as it would be viewed from within a function.
2524#[derive(Clone, Copy)]
2525pub enum DefinedTy<'tcx> {
2526    // Used for locals and closures defined within the function.
2527    Hir(&'tcx hir::Ty<'tcx>),
2528    /// Used for function signatures, and constant and static values. The type is
2529    /// in the context of its definition site. We also track the `def_id` of its
2530    /// definition site.
2531    ///
2532    /// WARNING: As the `ty` in in the scope of the definition, not of the function
2533    /// using it, you must be very careful with how you use it. Using it in the wrong
2534    /// scope easily results in ICEs.
2535    Mir {
2536        def_site_def_id: Option<DefId>,
2537        ty: Binder<'tcx, Ty<'tcx>>,
2538    },
2539}
2540
2541/// The context an expressions value is used in.
2542pub struct ExprUseCtxt<'tcx> {
2543    /// The parent node which consumes the value.
2544    pub node: Node<'tcx>,
2545    /// The child id of the node the value came from.
2546    pub child_id: HirId,
2547    /// Any adjustments applied to the type.
2548    pub adjustments: &'tcx [Adjustment<'tcx>],
2549    /// Whether the type must unify with another code path.
2550    pub is_ty_unified: bool,
2551    /// Whether the value will be moved before it's used.
2552    pub moved_before_use: bool,
2553    /// Whether the use site has the same `SyntaxContext` as the value.
2554    pub same_ctxt: bool,
2555}
2556impl<'tcx> ExprUseCtxt<'tcx> {
2557    pub fn use_node(&self, cx: &LateContext<'tcx>) -> ExprUseNode<'tcx> {
2558        match self.node {
2559            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
2560            Node::ExprField(field) => ExprUseNode::Field(field),
2561
2562            Node::Item(&Item {
2563                kind: ItemKind::Static(..) | ItemKind::Const(..),
2564                owner_id,
2565                ..
2566            })
2567            | Node::TraitItem(&TraitItem {
2568                kind: TraitItemKind::Const(..),
2569                owner_id,
2570                ..
2571            })
2572            | Node::ImplItem(&ImplItem {
2573                kind: ImplItemKind::Const(..),
2574                owner_id,
2575                ..
2576            }) => ExprUseNode::ConstStatic(owner_id),
2577
2578            Node::Item(&Item {
2579                kind: ItemKind::Fn { .. },
2580                owner_id,
2581                ..
2582            })
2583            | Node::TraitItem(&TraitItem {
2584                kind: TraitItemKind::Fn(..),
2585                owner_id,
2586                ..
2587            })
2588            | Node::ImplItem(&ImplItem {
2589                kind: ImplItemKind::Fn(..),
2590                owner_id,
2591                ..
2592            }) => ExprUseNode::Return(owner_id),
2593
2594            Node::Expr(use_expr) => match use_expr.kind {
2595                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
2596                    def_id: cx.tcx.hir_body_owner_def_id(cx.enclosing_body.unwrap()),
2597                }),
2598
2599                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
2600                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == self.child_id) {
2601                    Some(i) => ExprUseNode::FnArg(func, i),
2602                    None => ExprUseNode::Callee,
2603                },
2604                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
2605                    use_expr.hir_id,
2606                    name.args,
2607                    args.iter()
2608                        .position(|arg| arg.hir_id == self.child_id)
2609                        .map_or(0, |i| i + 1),
2610                ),
2611                ExprKind::Field(_, name) => ExprUseNode::FieldAccess(name),
2612                ExprKind::AddrOf(kind, mutbl, _) => ExprUseNode::AddrOf(kind, mutbl),
2613                _ => ExprUseNode::Other,
2614            },
2615            _ => ExprUseNode::Other,
2616        }
2617    }
2618}
2619
2620/// The node which consumes a value.
2621pub enum ExprUseNode<'tcx> {
2622    /// Assignment to, or initializer for, a local
2623    LetStmt(&'tcx LetStmt<'tcx>),
2624    /// Initializer for a const or static item.
2625    ConstStatic(OwnerId),
2626    /// Implicit or explicit return from a function.
2627    Return(OwnerId),
2628    /// Initialization of a struct field.
2629    Field(&'tcx ExprField<'tcx>),
2630    /// An argument to a function.
2631    FnArg(&'tcx Expr<'tcx>, usize),
2632    /// An argument to a method.
2633    MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
2634    /// The callee of a function call.
2635    Callee,
2636    /// Access of a field.
2637    FieldAccess(Ident),
2638    /// Borrow expression.
2639    AddrOf(ast::BorrowKind, Mutability),
2640    Other,
2641}
2642impl<'tcx> ExprUseNode<'tcx> {
2643    /// Checks if the value is returned from the function.
2644    pub fn is_return(&self) -> bool {
2645        matches!(self, Self::Return(_))
2646    }
2647
2648    /// Checks if the value is used as a method call receiver.
2649    pub fn is_recv(&self) -> bool {
2650        matches!(self, Self::MethodArg(_, _, 0))
2651    }
2652
2653    /// Gets the needed type as it's defined without any type inference.
2654    pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
2655        match *self {
2656            Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
2657            Self::ConstStatic(id) => Some(DefinedTy::Mir {
2658                def_site_def_id: Some(id.def_id.to_def_id()),
2659                ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()),
2660            }),
2661            Self::Return(id) => {
2662                if let Node::Expr(Expr {
2663                    kind: ExprKind::Closure(c),
2664                    ..
2665                }) = cx.tcx.hir_node_by_def_id(id.def_id)
2666                {
2667                    match c.fn_decl.output {
2668                        FnRetTy::DefaultReturn(_) => None,
2669                        FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
2670                    }
2671                } else {
2672                    let ty = cx.tcx.fn_sig(id).instantiate_identity().output();
2673                    Some(DefinedTy::Mir {
2674                        def_site_def_id: Some(id.def_id.to_def_id()),
2675                        ty,
2676                    })
2677                }
2678            },
2679            Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
2680                Some(Expr {
2681                    hir_id,
2682                    kind: ExprKind::Struct(path, ..),
2683                    ..
2684                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
2685                    .and_then(|(adt, variant)| {
2686                        variant
2687                            .fields
2688                            .iter()
2689                            .find(|f| f.name == field.ident.name)
2690                            .map(|f| (adt, f))
2691                    })
2692                    .map(|(adt, field_def)| DefinedTy::Mir {
2693                        def_site_def_id: Some(adt.did()),
2694                        ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()),
2695                    }),
2696                _ => None,
2697            },
2698            Self::FnArg(callee, i) => {
2699                let sig = expr_sig(cx, callee)?;
2700                let (hir_ty, ty) = sig.input_with_hir(i)?;
2701                Some(match hir_ty {
2702                    Some(hir_ty) => DefinedTy::Hir(hir_ty),
2703                    None => DefinedTy::Mir {
2704                        def_site_def_id: sig.predicates_id(),
2705                        ty,
2706                    },
2707                })
2708            },
2709            Self::MethodArg(id, _, i) => {
2710                let id = cx.typeck_results().type_dependent_def_id(id)?;
2711                let sig = cx.tcx.fn_sig(id).skip_binder();
2712                Some(DefinedTy::Mir {
2713                    def_site_def_id: Some(id),
2714                    ty: sig.input(i),
2715                })
2716            },
2717            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None,
2718        }
2719    }
2720}
2721
2722/// Gets the context an expression's value is used in.
2723pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtxt<'tcx> {
2724    let mut adjustments = [].as_slice();
2725    let mut is_ty_unified = false;
2726    let mut moved_before_use = false;
2727    let mut same_ctxt = true;
2728    let ctxt = e.span.ctxt();
2729    let node = walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| -> ControlFlow<!> {
2730        if adjustments.is_empty()
2731            && let Node::Expr(e) = cx.tcx.hir_node(child_id)
2732        {
2733            adjustments = cx.typeck_results().expr_adjustments(e);
2734        }
2735        same_ctxt &= cx.tcx.hir_span(parent_id).ctxt() == ctxt;
2736        if let Node::Expr(e) = parent {
2737            match e.kind {
2738                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
2739                    is_ty_unified = true;
2740                    moved_before_use = true;
2741                },
2742                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
2743                    is_ty_unified = true;
2744                    moved_before_use = true;
2745                },
2746                ExprKind::Block(..) => moved_before_use = true,
2747                _ => {},
2748            }
2749        }
2750        ControlFlow::Continue(())
2751    });
2752    match node {
2753        Some(ControlFlow::Continue((node, child_id))) => ExprUseCtxt {
2754            node,
2755            child_id,
2756            adjustments,
2757            is_ty_unified,
2758            moved_before_use,
2759            same_ctxt,
2760        },
2761        #[allow(unreachable_patterns)]
2762        Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
2763        None => ExprUseCtxt {
2764            node: Node::Crate(cx.tcx.hir_root_module()),
2765            child_id: HirId::INVALID,
2766            adjustments: &[],
2767            is_ty_unified: true,
2768            moved_before_use: true,
2769            same_ctxt: false,
2770        },
2771    }
2772}
2773
2774/// Tokenizes the input while keeping the text associated with each token.
2775pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, InnerSpan)> {
2776    let mut pos = 0;
2777    tokenize(s, FrontmatterAllowed::No).map(move |t| {
2778        let end = pos + t.len;
2779        let range = pos as usize..end as usize;
2780        let inner = InnerSpan::new(range.start, range.end);
2781        pos = end;
2782        (t.kind, s.get(range).unwrap_or_default(), inner)
2783    })
2784}
2785
2786/// Checks whether a given span has any comment token
2787/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
2788pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
2789    let Ok(snippet) = sm.span_to_snippet(span) else {
2790        return false;
2791    };
2792    return tokenize(&snippet, FrontmatterAllowed::No).any(|token| {
2793        matches!(
2794            token.kind,
2795            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
2796        )
2797    });
2798}
2799
2800/// Checks whether a given span has any significant token. A significant token is a non-whitespace
2801/// token, including comments unless `skip_comments` is set.
2802/// This is useful to determine if there are any actual code tokens in the span that are omitted in
2803/// the late pass, such as platform-specific code.
2804pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
2805    matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
2806        match token {
2807            TokenKind::Whitespace => false,
2808            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
2809            _ => true,
2810        }
2811    ))
2812}
2813/// Returns all the comments a given span contains
2814///
2815/// Comments are returned wrapped with their relevant delimiters
2816pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
2817    span_extract_comments(sm, span).join("\n")
2818}
2819
2820/// Returns all the comments a given span contains.
2821///
2822/// Comments are returned wrapped with their relevant delimiters.
2823pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec<String> {
2824    let snippet = sm.span_to_snippet(span).unwrap_or_default();
2825    tokenize_with_text(&snippet)
2826        .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
2827        .map(|(_, s, _)| s.to_string())
2828        .collect::<Vec<_>>()
2829}
2830
2831pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
2832    sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
2833}
2834
2835/// Returns whether the given let pattern and else body can be turned into the `?` operator
2836///
2837/// For this example:
2838/// ```ignore
2839/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None };
2840/// ```
2841/// We get as parameters:
2842/// ```ignore
2843/// pat: Some(a)
2844/// else_body: return None
2845/// ```
2846///
2847/// And for this example:
2848/// ```ignore
2849/// let Some(FooBar { a, b }) = ex else { return None };
2850/// ```
2851/// We get as parameters:
2852/// ```ignore
2853/// pat: Some(FooBar { a, b })
2854/// else_body: return None
2855/// ```
2856///
2857/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
2858/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not.
2859pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
2860    cx: &LateContext<'_>,
2861    pat: &'a Pat<'hir>,
2862    else_body: &Expr<'_>,
2863) -> Option<&'a Pat<'hir>> {
2864    if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind
2865        && is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome)
2866        && !is_refutable(cx, inner_pat)
2867        && let else_body = peel_blocks(else_body)
2868        && let ExprKind::Ret(Some(ret_val)) = else_body.kind
2869        && let ExprKind::Path(ret_path) = ret_val.kind
2870        && is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
2871    {
2872        Some(inner_pat)
2873    } else {
2874        None
2875    }
2876}
2877
2878macro_rules! op_utils {
2879    ($($name:ident $assign:ident)*) => {
2880        /// Binary operation traits like `LangItem::Add`
2881        pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
2882
2883        /// Operator-Assign traits like `LangItem::AddAssign`
2884        pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
2885
2886        /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
2887        pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
2888            match kind {
2889                $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
2890                _ => None,
2891            }
2892        }
2893    };
2894}
2895
2896op_utils! {
2897    Add    AddAssign
2898    Sub    SubAssign
2899    Mul    MulAssign
2900    Div    DivAssign
2901    Rem    RemAssign
2902    BitXor BitXorAssign
2903    BitAnd BitAndAssign
2904    BitOr  BitOrAssign
2905    Shl    ShlAssign
2906    Shr    ShrAssign
2907}
2908
2909/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
2910/// that is not locally used.
2911pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool {
2912    match *pat {
2913        PatKind::Wild => true,
2914        PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => {
2915            !visitors::is_local_used(cx, body, id)
2916        },
2917        _ => false,
2918    }
2919}
2920
2921#[derive(Clone, Copy)]
2922pub enum RequiresSemi {
2923    Yes,
2924    No,
2925}
2926impl RequiresSemi {
2927    pub fn requires_semi(self) -> bool {
2928        matches!(self, Self::Yes)
2929    }
2930}
2931
2932/// Check if the expression return `!`, a type coerced from `!`, or could return `!` if the final
2933/// expression were turned into a statement.
2934#[expect(clippy::too_many_lines)]
2935pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<RequiresSemi> {
2936    struct BreakTarget {
2937        id: HirId,
2938        unused: bool,
2939    }
2940
2941    struct V<'cx, 'tcx> {
2942        cx: &'cx LateContext<'tcx>,
2943        break_targets: Vec<BreakTarget>,
2944        break_targets_for_result_ty: u32,
2945        in_final_expr: bool,
2946        requires_semi: bool,
2947        is_never: bool,
2948    }
2949
2950    impl V<'_, '_> {
2951        fn push_break_target(&mut self, id: HirId) {
2952            self.break_targets.push(BreakTarget { id, unused: true });
2953            self.break_targets_for_result_ty += u32::from(self.in_final_expr);
2954        }
2955    }
2956
2957    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
2958        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
2959            // Note: Part of the complexity here comes from the fact that
2960            // coercions are applied to the innermost expression.
2961            // e.g. In `let x: u32 = { break () };` the never-to-any coercion
2962            // is applied to the break expression. This means we can't just
2963            // check the block's type as it will be `u32` despite the fact
2964            // that the block always diverges.
2965
2966            // The rest of the complexity comes from checking blocks which
2967            // syntactically return a value, but will always diverge before
2968            // reaching that point.
2969            // e.g. In `let x = { foo(panic!()) };` the block's type will be the
2970            // return type of `foo` even though it will never actually run. This
2971            // can be trivially fixed by adding a semicolon after the call, but
2972            // we must first detect that a semicolon is needed to make that
2973            // suggestion.
2974
2975            if self.is_never && self.break_targets.is_empty() {
2976                if self.in_final_expr && !self.requires_semi {
2977                    // This expression won't ever run, but we still need to check
2978                    // if it can affect the type of the final expression.
2979                    match e.kind {
2980                        ExprKind::DropTemps(e) => self.visit_expr(e),
2981                        ExprKind::If(_, then, Some(else_)) => {
2982                            self.visit_expr(then);
2983                            self.visit_expr(else_);
2984                        },
2985                        ExprKind::Match(_, arms, _) => {
2986                            for arm in arms {
2987                                self.visit_expr(arm.body);
2988                            }
2989                        },
2990                        ExprKind::Loop(b, ..) => {
2991                            self.push_break_target(e.hir_id);
2992                            self.in_final_expr = false;
2993                            self.visit_block(b);
2994                            self.break_targets.pop();
2995                        },
2996                        ExprKind::Block(b, _) => {
2997                            if b.targeted_by_break {
2998                                self.push_break_target(b.hir_id);
2999                                self.visit_block(b);
3000                                self.break_targets.pop();
3001                            } else {
3002                                self.visit_block(b);
3003                            }
3004                        },
3005                        _ => {
3006                            self.requires_semi = !self.cx.typeck_results().expr_ty(e).is_never();
3007                        },
3008                    }
3009                }
3010                return;
3011            }
3012            match e.kind {
3013                ExprKind::DropTemps(e) => self.visit_expr(e),
3014                ExprKind::Ret(None) | ExprKind::Continue(_) => self.is_never = true,
3015                ExprKind::Ret(Some(e)) | ExprKind::Become(e) => {
3016                    self.in_final_expr = false;
3017                    self.visit_expr(e);
3018                    self.is_never = true;
3019                },
3020                ExprKind::Break(dest, e) => {
3021                    if let Some(e) = e {
3022                        self.in_final_expr = false;
3023                        self.visit_expr(e);
3024                    }
3025                    if let Ok(id) = dest.target_id
3026                        && let Some((i, target)) = self
3027                            .break_targets
3028                            .iter_mut()
3029                            .enumerate()
3030                            .find(|(_, target)| target.id == id)
3031                    {
3032                        target.unused &= self.is_never;
3033                        if i < self.break_targets_for_result_ty as usize {
3034                            self.requires_semi = true;
3035                        }
3036                    }
3037                    self.is_never = true;
3038                },
3039                ExprKind::If(cond, then, else_) => {
3040                    let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3041                    self.visit_expr(cond);
3042                    self.in_final_expr = in_final_expr;
3043
3044                    if self.is_never {
3045                        self.visit_expr(then);
3046                        if let Some(else_) = else_ {
3047                            self.visit_expr(else_);
3048                        }
3049                    } else {
3050                        self.visit_expr(then);
3051                        let is_never = mem::replace(&mut self.is_never, false);
3052                        if let Some(else_) = else_ {
3053                            self.visit_expr(else_);
3054                            self.is_never &= is_never;
3055                        }
3056                    }
3057                },
3058                ExprKind::Match(scrutinee, arms, _) => {
3059                    let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3060                    self.visit_expr(scrutinee);
3061                    self.in_final_expr = in_final_expr;
3062
3063                    if self.is_never {
3064                        for arm in arms {
3065                            self.visit_arm(arm);
3066                        }
3067                    } else {
3068                        let mut is_never = true;
3069                        for arm in arms {
3070                            self.is_never = false;
3071                            if let Some(guard) = arm.guard {
3072                                let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3073                                self.visit_expr(guard);
3074                                self.in_final_expr = in_final_expr;
3075                                // The compiler doesn't consider diverging guards as causing the arm to diverge.
3076                                self.is_never = false;
3077                            }
3078                            self.visit_expr(arm.body);
3079                            is_never &= self.is_never;
3080                        }
3081                        self.is_never = is_never;
3082                    }
3083                },
3084                ExprKind::Loop(b, _, _, _) => {
3085                    self.push_break_target(e.hir_id);
3086                    self.in_final_expr = false;
3087                    self.visit_block(b);
3088                    self.is_never = self.break_targets.pop().unwrap().unused;
3089                },
3090                ExprKind::Block(b, _) => {
3091                    if b.targeted_by_break {
3092                        self.push_break_target(b.hir_id);
3093                        self.visit_block(b);
3094                        self.is_never &= self.break_targets.pop().unwrap().unused;
3095                    } else {
3096                        self.visit_block(b);
3097                    }
3098                },
3099                _ => {
3100                    self.in_final_expr = false;
3101                    walk_expr(self, e);
3102                    self.is_never |= self.cx.typeck_results().expr_ty(e).is_never();
3103                },
3104            }
3105        }
3106
3107        fn visit_block(&mut self, b: &'tcx Block<'_>) {
3108            let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3109            for s in b.stmts {
3110                self.visit_stmt(s);
3111            }
3112            self.in_final_expr = in_final_expr;
3113            if let Some(e) = b.expr {
3114                self.visit_expr(e);
3115            }
3116        }
3117
3118        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
3119            if let Some(e) = l.init {
3120                self.visit_expr(e);
3121            }
3122            if let Some(else_) = l.els {
3123                let is_never = self.is_never;
3124                self.visit_block(else_);
3125                self.is_never = is_never;
3126            }
3127        }
3128
3129        fn visit_arm(&mut self, arm: &Arm<'tcx>) {
3130            if let Some(guard) = arm.guard {
3131                let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3132                self.visit_expr(guard);
3133                self.in_final_expr = in_final_expr;
3134            }
3135            self.visit_expr(arm.body);
3136        }
3137    }
3138
3139    if cx.typeck_results().expr_ty(e).is_never() {
3140        Some(RequiresSemi::No)
3141    } else if let ExprKind::Block(b, _) = e.kind
3142        && !b.targeted_by_break
3143        && b.expr.is_none()
3144    {
3145        // If a block diverges without a final expression then it's type is `!`.
3146        None
3147    } else {
3148        let mut v = V {
3149            cx,
3150            break_targets: Vec::new(),
3151            break_targets_for_result_ty: 0,
3152            in_final_expr: true,
3153            requires_semi: false,
3154            is_never: false,
3155        };
3156        v.visit_expr(e);
3157        v.is_never
3158            .then_some(if v.requires_semi && matches!(e.kind, ExprKind::Block(..)) {
3159                RequiresSemi::Yes
3160            } else {
3161                RequiresSemi::No
3162            })
3163    }
3164}
3165
3166/// Produces a path from a local caller to the type of the called method. Suitable for user
3167/// output/suggestions.
3168///
3169/// Returned path can be either absolute (for methods defined non-locally), or relative (for local
3170/// methods).
3171pub fn get_path_from_caller_to_method_type<'tcx>(
3172    tcx: TyCtxt<'tcx>,
3173    from: LocalDefId,
3174    method: DefId,
3175    args: GenericArgsRef<'tcx>,
3176) -> String {
3177    let assoc_item = tcx.associated_item(method);
3178    let def_id = assoc_item.container_id(tcx);
3179    match assoc_item.container {
3180        rustc_ty::AssocItemContainer::Trait => get_path_to_callee(tcx, from, def_id),
3181        rustc_ty::AssocItemContainer::Impl => {
3182            let ty = tcx.type_of(def_id).instantiate_identity();
3183            get_path_to_ty(tcx, from, ty, args)
3184        },
3185    }
3186}
3187
3188fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args: GenericArgsRef<'tcx>) -> String {
3189    match ty.kind() {
3190        rustc_ty::Adt(adt, _) => get_path_to_callee(tcx, from, adt.did()),
3191        // TODO these types need to be recursively resolved as well
3192        rustc_ty::Array(..)
3193        | rustc_ty::Dynamic(..)
3194        | rustc_ty::Never
3195        | rustc_ty::RawPtr(_, _)
3196        | rustc_ty::Ref(..)
3197        | rustc_ty::Slice(_)
3198        | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)),
3199        _ => ty.to_string(),
3200    }
3201}
3202
3203/// Produce a path from some local caller to the callee. Suitable for user output/suggestions.
3204fn get_path_to_callee(tcx: TyCtxt<'_>, from: LocalDefId, callee: DefId) -> String {
3205    // only search for a relative path if the call is fully local
3206    if callee.is_local() {
3207        let callee_path = tcx.def_path(callee);
3208        let caller_path = tcx.def_path(from.to_def_id());
3209        maybe_get_relative_path(&caller_path, &callee_path, 2)
3210    } else {
3211        tcx.def_path_str(callee)
3212    }
3213}
3214
3215/// Tries to produce a relative path from `from` to `to`; if such a path would contain more than
3216/// `max_super` `super` items, produces an absolute path instead. Both `from` and `to` should be in
3217/// the local crate.
3218///
3219/// Suitable for user output/suggestions.
3220///
3221/// This ignores use items, and assumes that the target path is visible from the source
3222/// path (which _should_ be a reasonable assumption since we in order to be able to use an object of
3223/// certain type T, T is required to be visible).
3224///
3225/// TODO make use of `use` items. Maybe we should have something more sophisticated like
3226/// rust-analyzer does? <https://docs.rs/ra_ap_hir_def/0.0.169/src/ra_ap_hir_def/find_path.rs.html#19-27>
3227fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> String {
3228    use itertools::EitherOrBoth::{Both, Left, Right};
3229
3230    // 1. skip the segments common for both paths (regardless of their type)
3231    let unique_parts = to
3232        .data
3233        .iter()
3234        .zip_longest(from.data.iter())
3235        .skip_while(|el| matches!(el, Both(l, r) if l == r))
3236        .map(|el| match el {
3237            Both(l, r) => Both(l.data, r.data),
3238            Left(l) => Left(l.data),
3239            Right(r) => Right(r.data),
3240        });
3241
3242    // 2. for the remaining segments, construct relative path using only mod names and `super`
3243    let mut go_up_by = 0;
3244    let mut path = Vec::new();
3245    for el in unique_parts {
3246        match el {
3247            Both(l, r) => {
3248                // consider:
3249                // a::b::sym:: ::    refers to
3250                // c::d::e  ::f::sym
3251                // result should be super::super::c::d::e::f
3252                //
3253                // alternatively:
3254                // a::b::c  ::d::sym refers to
3255                // e::f::sym:: ::
3256                // result should be super::super::super::super::e::f
3257                if let DefPathData::TypeNs(sym) = l {
3258                    path.push(sym);
3259                }
3260                if let DefPathData::TypeNs(_) = r {
3261                    go_up_by += 1;
3262                }
3263            },
3264            // consider:
3265            // a::b::sym:: ::    refers to
3266            // c::d::e  ::f::sym
3267            // when looking at `f`
3268            Left(DefPathData::TypeNs(sym)) => path.push(sym),
3269            // consider:
3270            // a::b::c  ::d::sym refers to
3271            // e::f::sym:: ::
3272            // when looking at `d`
3273            Right(DefPathData::TypeNs(_)) => go_up_by += 1,
3274            _ => {},
3275        }
3276    }
3277
3278    if go_up_by > max_super {
3279        // `super` chain would be too long, just use the absolute path instead
3280        join_path_syms(once(kw::Crate).chain(to.data.iter().filter_map(|el| {
3281            if let DefPathData::TypeNs(sym) = el.data {
3282                Some(sym)
3283            } else {
3284                None
3285            }
3286        })))
3287    } else {
3288        join_path_syms(repeat_n(kw::Super, go_up_by).chain(path))
3289    }
3290}
3291
3292/// Returns true if the specified `HirId` is the top-level expression of a statement or the only
3293/// expression in a block.
3294pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
3295    matches!(
3296        cx.tcx.parent_hir_node(id),
3297        Node::Stmt(..) | Node::Block(Block { stmts: [], .. })
3298    )
3299}
3300
3301/// Returns true if the given `expr` is a block or resembled as a block,
3302/// such as `if`, `loop`, `match` expressions etc.
3303pub fn is_block_like(expr: &Expr<'_>) -> bool {
3304    matches!(
3305        expr.kind,
3306        ExprKind::Block(..) | ExprKind::ConstBlock(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..)
3307    )
3308}
3309
3310/// Returns true if the given `expr` is binary expression that needs to be wrapped in parentheses.
3311pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool {
3312    fn contains_block(expr: &Expr<'_>, is_operand: bool) -> bool {
3313        match expr.kind {
3314            ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => contains_block(lhs, true),
3315            _ if is_block_like(expr) => is_operand,
3316            _ => false,
3317        }
3318    }
3319
3320    contains_block(expr, false)
3321}
3322
3323/// Returns true if the specified expression is in a receiver position.
3324pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3325    if let Some(parent_expr) = get_parent_expr(cx, expr)
3326        && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind
3327        && receiver.hir_id == expr.hir_id
3328    {
3329        return true;
3330    }
3331    false
3332}
3333
3334/// Returns true if `expr` creates any temporary whose type references a non-static lifetime and has
3335/// a significant drop and does not consume it.
3336pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
3337    for_each_unconsumed_temporary(cx, expr, |temporary_ty| {
3338        if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env())
3339            && temporary_ty
3340                .walk()
3341                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
3342        {
3343            ControlFlow::Break(())
3344        } else {
3345            ControlFlow::Continue(())
3346        }
3347    })
3348    .is_break()
3349}
3350
3351/// Returns true if the specified `expr` requires coercion,
3352/// meaning that it either has a coercion or propagates a coercion from one of its sub expressions.
3353///
3354/// Similar to [`is_adjusted`], this not only checks if an expression's type was adjusted,
3355/// but also going through extra steps to see if it fits the description of [coercion sites].
3356///
3357/// You should used this when you want to avoid suggesting replacing an expression that is currently
3358/// a coercion site or coercion propagating expression with one that is not.
3359///
3360/// [coercion sites]: https://doc.rust-lang.org/stable/reference/type-coercions.html#coercion-sites
3361pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
3362    let expr_ty_is_adjusted = cx
3363        .typeck_results()
3364        .expr_adjustments(expr)
3365        .iter()
3366        // ignore `NeverToAny` adjustments, such as `panic!` call.
3367        .any(|adj| !matches!(adj.kind, Adjust::NeverToAny));
3368    if expr_ty_is_adjusted {
3369        return true;
3370    }
3371
3372    // Identify coercion sites and recursively check if those sites
3373    // actually have type adjustments.
3374    match expr.kind {
3375        ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => {
3376            let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
3377
3378            if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) {
3379                return false;
3380            }
3381
3382            let self_arg_count = usize::from(matches!(expr.kind, ExprKind::MethodCall(..)));
3383            let mut args_with_ty_param = {
3384                fn_sig
3385                    .inputs()
3386                    .skip_binder()
3387                    .iter()
3388                    .skip(self_arg_count)
3389                    .zip(args)
3390                    .filter_map(|(arg_ty, arg)| {
3391                        if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) {
3392                            Some(arg)
3393                        } else {
3394                            None
3395                        }
3396                    })
3397            };
3398            args_with_ty_param.any(|arg| expr_requires_coercion(cx, arg))
3399        },
3400        // Struct/union initialization.
3401        ExprKind::Struct(qpath, _, _) => {
3402            let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
3403            if let Some((_, v_def)) = adt_and_variant_of_res(cx, res) {
3404                let rustc_ty::Adt(_, generic_args) = cx.typeck_results().expr_ty_adjusted(expr).kind() else {
3405                    // This should never happen, but when it does, not linting is the better option.
3406                    return true;
3407                };
3408                v_def
3409                    .fields
3410                    .iter()
3411                    .any(|field| field.ty(cx.tcx, generic_args).has_type_flags(TypeFlags::HAS_TY_PARAM))
3412            } else {
3413                false
3414            }
3415        },
3416        // Function results, including the final line of a block or a `return` expression.
3417        ExprKind::Block(
3418            &Block {
3419                expr: Some(ret_expr), ..
3420            },
3421            _,
3422        )
3423        | ExprKind::Ret(Some(ret_expr)) => expr_requires_coercion(cx, ret_expr),
3424
3425        // ===== Coercion-propagation expressions =====
3426        ExprKind::Array(elems) | ExprKind::Tup(elems) => elems.iter().any(|elem| expr_requires_coercion(cx, elem)),
3427        // Array but with repeating syntax.
3428        ExprKind::Repeat(rep_elem, _) => expr_requires_coercion(cx, rep_elem),
3429        // Others that may contain coercion sites.
3430        ExprKind::If(_, then, maybe_else) => {
3431            expr_requires_coercion(cx, then) || maybe_else.is_some_and(|e| expr_requires_coercion(cx, e))
3432        },
3433        ExprKind::Match(_, arms, _) => arms
3434            .iter()
3435            .map(|arm| arm.body)
3436            .any(|body| expr_requires_coercion(cx, body)),
3437        _ => false,
3438    }
3439}
3440
3441/// Returns `true` if `expr` designates a mutable static, a mutable local binding, or an expression
3442/// that can be owned.
3443pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3444    if let Some(hir_id) = path_to_local(expr)
3445        && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
3446    {
3447        matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
3448    } else if let ExprKind::Path(p) = &expr.kind
3449        && let Some(mutability) = cx
3450            .qpath_res(p, expr.hir_id)
3451            .opt_def_id()
3452            .and_then(|id| cx.tcx.static_mutability(id))
3453    {
3454        mutability == Mutability::Mut
3455    } else if let ExprKind::Field(parent, _) = expr.kind {
3456        is_mutable(cx, parent)
3457    } else {
3458        true
3459    }
3460}
3461
3462/// Peel `Option<…>` from `hir_ty` as long as the HIR name is `Option` and it corresponds to the
3463/// `core::Option<_>` type.
3464pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
3465    let Some(option_def_id) = cx.tcx.get_diagnostic_item(sym::Option) else {
3466        return hir_ty;
3467    };
3468    while let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind
3469        && let Some(segment) = path.segments.last()
3470        && segment.ident.name == sym::Option
3471        && let Res::Def(DefKind::Enum, def_id) = segment.res
3472        && def_id == option_def_id
3473        && let [GenericArg::Type(arg_ty)] = segment.args().args
3474    {
3475        hir_ty = arg_ty.as_unambig_ty();
3476    }
3477    hir_ty
3478}
3479
3480/// If `expr` is a desugared `.await`, return the original expression if it does not come from a
3481/// macro expansion.
3482pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
3483    if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind
3484        && let ExprKind::Call(_, [into_future_arg]) = match_value.kind
3485        && let ctxt = expr.span.ctxt()
3486        && for_each_expr_without_closures(into_future_arg, |e| {
3487            walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))
3488        })
3489        .is_none()
3490    {
3491        Some(into_future_arg)
3492    } else {
3493        None
3494    }
3495}
3496
3497/// Checks if the given expression is a call to `Default::default()`.
3498pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
3499    if let ExprKind::Call(fn_expr, []) = &expr.kind
3500        && let ExprKind::Path(qpath) = &fn_expr.kind
3501        && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
3502    {
3503        cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
3504    } else {
3505        false
3506    }
3507}
3508
3509/// Checks if `expr` may be directly used as the return value of its enclosing body.
3510/// The following cases are covered:
3511/// - `expr` as the last expression of the body, or of a block that can be used as the return value
3512/// - `return expr`
3513/// - then or else part of a `if` in return position
3514/// - arm body of a `match` in a return position
3515/// - `break expr` or `break 'label expr` if the loop or block being exited is used as a return
3516///   value
3517///
3518/// Contrary to [`TyCtxt::hir_get_fn_id_for_return_block()`], if `expr` is part of a
3519/// larger expression, for example a field expression of a `struct`, it will not be
3520/// considered as matching the condition and will return `false`.
3521///
3522/// Also, even if `expr` is assigned to a variable which is later returned, this function
3523/// will still return `false` because `expr` is not used *directly* as the return value
3524/// as it goes through the intermediate variable.
3525pub fn potential_return_of_enclosing_body(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3526    let enclosing_body_owner = cx
3527        .tcx
3528        .local_def_id_to_hir_id(cx.tcx.hir_enclosing_body_owner(expr.hir_id));
3529    let mut prev_id = expr.hir_id;
3530    let mut skip_until_id = None;
3531    for (hir_id, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
3532        if hir_id == enclosing_body_owner {
3533            return true;
3534        }
3535        if let Some(id) = skip_until_id {
3536            prev_id = hir_id;
3537            if id == hir_id {
3538                skip_until_id = None;
3539            }
3540            continue;
3541        }
3542        match node {
3543            Node::Block(Block { expr, .. }) if expr.is_some_and(|expr| expr.hir_id == prev_id) => {},
3544            Node::Arm(arm) if arm.body.hir_id == prev_id => {},
3545            Node::Expr(expr) => match expr.kind {
3546                ExprKind::Ret(_) => return true,
3547                ExprKind::If(_, then, opt_else)
3548                    if then.hir_id == prev_id || opt_else.is_some_and(|els| els.hir_id == prev_id) => {},
3549                ExprKind::Match(_, arms, _) if arms.iter().any(|arm| arm.hir_id == prev_id) => {},
3550                ExprKind::Block(block, _) if block.hir_id == prev_id => {},
3551                ExprKind::Break(
3552                    Destination {
3553                        target_id: Ok(target_id),
3554                        ..
3555                    },
3556                    _,
3557                ) => skip_until_id = Some(target_id),
3558                _ => break,
3559            },
3560            _ => break,
3561        }
3562        prev_id = hir_id;
3563    }
3564
3565    // `expr` is used as part of "something" and is not returned directly from its
3566    // enclosing body.
3567    false
3568}
3569
3570/// Checks if the expression has adjustments that require coercion, for example: dereferencing with
3571/// overloaded deref, coercing pointers and `dyn` objects.
3572pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3573    cx.typeck_results().expr_adjustments(expr).iter().any(|adj| {
3574        matches!(
3575            adj.kind,
3576            Adjust::Deref(Some(_)) | Adjust::Pointer(PointerCoercion::Unsize) | Adjust::NeverToAny
3577        )
3578    })
3579}