clippy_utils/
lib.rs

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