Skip to main content

clippy_utils/
lib.rs

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