Skip to main content

clippy_utils/
lib.rs

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