Skip to main content

clippy_utils/
lib.rs

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