Skip to main content

clippy_utils/
lib.rs

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