Skip to main content

clippy_utils/
lib.rs

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