Skip to main content

clippy_utils/
lib.rs

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