Skip to main content

clippy_utils/
lib.rs

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