Skip to main content

clippy_utils/
lib.rs

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