Skip to main content

clippy_utils/
lib.rs

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