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