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