Skip to main content

clippy_utils/
lib.rs

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