src/tools/clippy/clippy_utils/src/lib.rs RUST 3,692 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,692.
1#![feature(deref_patterns)]2#![feature(macro_metavar_expr)]3#![feature(rustc_private)]4#![feature(unwrap_infallible)]5#![recursion_limit = "512"]6#![expect(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]7#![warn(8    rust_2018_idioms,9    trivial_casts,10    trivial_numeric_casts,11    unused_lifetimes,12    unused_qualifications,13    rustc::internal14)]1516// FIXME: switch to something more ergonomic here, once available.17// (Currently there is no way to opt into sysroot crates without `extern crate`.)18extern crate rustc_abi;19extern crate rustc_ast;20extern crate rustc_attr_parsing;21extern crate rustc_const_eval;22extern crate rustc_data_structures;23#[expect(24    unused_extern_crates,25    reason = "The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate."26)]27extern crate rustc_driver;28extern crate rustc_errors;29extern crate rustc_hir;30extern crate rustc_hir_analysis;31extern crate rustc_hir_typeck;32extern crate rustc_index;33extern crate rustc_infer;34extern crate rustc_lexer;35extern crate rustc_lint;36extern crate rustc_middle;37extern crate rustc_mir_dataflow;38extern crate rustc_session;39extern crate rustc_span;40extern crate rustc_trait_selection;4142pub mod ast_utils;43#[deny(missing_docs)]44pub mod attrs;45mod check_proc_macro;46pub mod comparisons;47pub mod consts;48pub mod diagnostics;49pub mod eager_or_lazy;50pub mod higher;51mod hir_utils;52pub mod macros;53pub mod mir;54pub mod msrvs;55pub mod numeric_literal;56pub mod paths;57pub mod qualify_min_const_fn;58pub mod res;59pub mod source;60pub mod str_utils;61pub mod sugg;62pub mod sym;63pub mod ty;64pub mod usage;65pub mod visitors;6667pub use self::attrs::*;68pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};69pub use self::hir_utils::{70    HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, has_ambiguous_literal_in_expr, hash_expr,71    hash_stmt, is_bool, over,72};7374use core::mem;75use core::ops::ControlFlow;76use std::collections::hash_map::Entry;77use std::iter::{once, repeat_n, zip};78use std::sync::{Mutex, OnceLock};7980use itertools::Itertools as _;81use rustc_abi::Integer;82use rustc_ast::ast::{self, LitKind, RangeLimits};83use rustc_ast::{LitIntType, join_path_syms};84use rustc_data_structures::fx::FxHashMap;85use rustc_data_structures::indexmap;86use rustc_data_structures::packed::Pu128;87use rustc_data_structures::unhash::UnindexMap;88use rustc_hir::attrs::CfgEntry;89use rustc_hir::attrs::lang_items::LangItem;90use rustc_hir::attrs::lang_items::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};91use rustc_hir::def::{DefKind, Res};92use rustc_hir::def_id::{DefId, LocalDefId, LocalModId};93use rustc_hir::definitions::{DefPath, DefPathData};94use rustc_hir::intravisit::{Visitor, walk_expr};95use rustc_hir::{96    self as hir, AnonConst, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, CRATE_HIR_ID, Closure, ConstArg,97    ConstArgKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Destination, Expr, ExprField, ExprKind,98    FieldDef, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, HirIdSet, Impl, ImplItem, ImplItemKind, Item,99    ItemKind, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind,100    Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, Variant, def,101    find_attr,102};103use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};104use rustc_lint::{LateContext, Level, Lint, LintContext as _};105use rustc_middle::hir::nested_filter;106use rustc_middle::hir::place::PlaceBase;107use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};108use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, DerefAdjustKind, PointerCoercion};109use rustc_middle::ty::layout::IntegerExt as _;110use rustc_middle::ty::{111    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt,112    TypeFlags, TypeVisitableExt as _, TypeckResults, UintTy, UpvarCapture,113};114use rustc_span::hygiene::{ExpnKind, MacroKind};115use rustc_span::source_map::SourceMap;116use rustc_span::symbol::{Ident, Symbol, kw};117use rustc_span::{InnerSpan, Span, SyntaxContext};118use source::{SpanExt as _, walk_span_to_context};119use visitors::{Visitable, for_each_unconsumed_temporary};120121use crate::ast_utils::unordered_over;122use crate::higher::Range;123use crate::msrvs::Msrv;124use crate::res::{MaybeDef as _, MaybeResPath as _};125use crate::source::HasSourceMap;126use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};127use crate::visitors::for_each_expr_without_closures;128129/// Methods on `Vec` that also exists on slices.130pub const VEC_METHODS_SHADOWING_SLICE_METHODS: [Symbol; 3] = [sym::as_ptr, sym::is_empty, sym::len];131132#[macro_export]133macro_rules! extract_msrv_attr {134    () => {135        fn check_attributes(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::ast::Attribute]) {136            let sess = rustc_lint::LintContext::sess(cx);137            self.msrv.check_attributes(attrs);138        }139140        fn check_attributes_post(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::ast::Attribute]) {141            let sess = rustc_lint::LintContext::sess(cx);142            self.msrv.check_attributes_post(attrs);143        }144    };145}146147/// If the given expression is a local binding, find the initializer expression.148/// If that initializer expression is another local binding, find its initializer again.149///150/// This process repeats as long as possible (but usually no more than once). Initializer151/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]152/// instead.153///154/// Examples:155/// ```no_run156/// let abc = 1;157/// //        ^ output158/// let def = abc;159/// dbg!(def);160/// //   ^^^ input161///162/// // or...163/// let abc = 1;164/// let def = abc + 2;165/// //        ^^^^^^^ output166/// dbg!(def);167/// //   ^^^ input168/// ```169pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {170    while let Some(init) = expr171        .res_local_id()172        .and_then(|id| find_binding_init(cx, id))173        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())174    {175        expr = init;176    }177    expr178}179180/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.181///182/// By only considering immutable bindings, we guarantee that the returned expression represents the183/// value of the binding wherever it is referenced.184///185/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.186/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the187/// canonical binding `HirId`.188pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {189    if let Node::Pat(pat) = cx.tcx.hir_node(hir_id)190        && matches!(pat.kind, PatKind::Binding(BindingMode::NONE, ..))191        && let Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id)192    {193        return local.init;194    }195    None196}197198/// Checks if the given local has an initializer or is from something other than a `let` statement199///200/// e.g. returns true for `x` in `fn f(x: usize) { .. }` and `let x = 1;` but false for `let x;`201pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {202    for (_, node) in cx.tcx.hir_parent_iter(local) {203        match node {204            Node::Pat(..) | Node::PatField(..) => {},205            Node::LetStmt(let_stmt) => return let_stmt.init.is_some(),206            _ => return true,207        }208    }209210    false211}212213/// Checks if we are currently in a const context (e.g. `const fn`, `static`/`const` initializer).214///215/// The current context is determined based on the current body which is set before calling a lint's216/// entry point (any function on `LateLintPass`). If you need to check in a different context use217/// `tcx.hir_is_inside_const_context(_)`.218///219/// Do not call this unless the `LateContext` has an enclosing body. For release build this case220/// will safely return `false`, but debug builds will ICE. Note that `check_expr`, `check_block`,221/// `check_pat` and a few other entry points will always have an enclosing body. Some entry points222/// like `check_path` or `check_ty` may or may not have one.223pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {224    debug_assert!(cx.enclosing_body.is_some(), "`LateContext` has no enclosing body");225    cx.enclosing_body.is_some_and(|id| {226        cx.tcx227            .hir_body_const_context(cx.tcx.hir_body_owner_def_id(id))228            .is_some()229    })230}231232/// Returns `true` if the given `HirId` is inside an always constant context.233///234/// This context includes:235///  * const/static items236///  * const blocks (or inline consts)237///  * associated constants238pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {239    use rustc_hir::ConstContext::{Const, ConstFn, Static};240    let Some(ctx) = tcx.hir_body_const_context(tcx.hir_enclosing_body_owner(hir_id)) else {241        return false;242    };243    match ctx {244        ConstFn => false,245        Static(_)246        | Const {247            allow_const_fn_promotion: _,248        } => true,249    }250}251252/// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`.253pub fn is_enum_variant_ctor(254    cx: &LateContext<'_>,255    enum_item: Symbol,256    variant_name: Symbol,257    ctor_call_id: DefId,258) -> bool {259    let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else {260        return false;261    };262263    let variants = cx.tcx.adt_def(enum_def_id).variants().iter();264    variants265        .filter(|variant| variant.name == variant_name)266        .filter_map(|variant| variant.ctor.as_ref())267        .any(|(_, ctor_def_id)| *ctor_def_id == ctor_call_id)268}269270/// Checks if the `DefId` matches the given diagnostic item or it's constructor.271pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool {272    let did = match cx.tcx.def_kind(did) {273        DefKind::Ctor(..) => cx.tcx.parent(did),274        // Constructors for types in external crates seem to have `DefKind::Variant`275        DefKind::Variant => match cx.tcx.opt_parent(did) {276            Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,277            _ => did,278        },279        _ => did,280    };281282    cx.tcx.is_diagnostic_item(item, did)283}284285/// Checks if the `DefId` matches the given `LangItem` or it's constructor.286pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool {287    let did = match cx.tcx.def_kind(did) {288        DefKind::Ctor(..) => cx.tcx.parent(did),289        // Constructors for types in external crates seem to have `DefKind::Variant`290        DefKind::Variant => match cx.tcx.opt_parent(did) {291            Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,292            _ => did,293        },294        _ => did,295    };296297    cx.tcx.lang_items().get(item) == Some(did)298}299300/// Checks is `expr` is `None`301pub fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {302    expr.basic_res().ctor_parent(cx).is_lang_item(cx, OptionNone)303}304305/// If `expr` is `Some(inner)`, returns `inner`306pub fn as_some_expr<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {307    if let ExprKind::Call(e, [arg]) = expr.kind308        && e.basic_res().ctor_parent(cx).is_lang_item(cx, OptionSome)309    {310        Some(arg)311    } else {312        None313    }314}315316/// Check if the given `Expr` is an empty block (i.e. `{}`) or not.317pub fn is_empty_block(expr: &Expr<'_>) -> bool {318    matches!(319        expr.kind,320        ExprKind::Block(321            Block {322                stmts: [],323                expr: None,324                ..325            },326            _,327        )328    )329}330331/// Checks if `expr` is an empty block or an empty tuple.332pub fn is_unit_expr(expr: &Expr<'_>) -> bool {333    matches!(334        expr.kind,335        ExprKind::Block(336            Block {337                stmts: [],338                expr: None,339                ..340            },341            _342        ) | ExprKind::Tup([])343    )344}345346/// Checks if given pattern is a wildcard (`_`)347pub fn is_wild(pat: &Pat<'_>) -> bool {348    matches!(pat.kind, PatKind::Wild)349}350351/// If `pat` is:352/// - `Some(inner)`, returns `inner`353///    - it will _usually_ contain just one element, but could have two, given patterns like354///      `Some(inner, ..)` or `Some(.., inner)`355/// - `Some`, returns `[]`356/// - otherwise, returns `None`357pub fn as_some_pattern<'a, 'hir>(cx: &LateContext<'_>, pat: &'a Pat<'hir>) -> Option<&'a [Pat<'hir>]> {358    if let PatKind::TupleStruct(ref qpath, inner, _) = pat.kind359        && cx360            .qpath_res(qpath, pat.hir_id)361            .ctor_parent(cx)362            .is_lang_item(cx, OptionSome)363    {364        Some(inner)365    } else {366        None367    }368}369370/// Checks if the `pat` is `None`.371pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {372    matches!(pat.kind,373        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })374            if cx.qpath_res(qpath, pat.hir_id).ctor_parent(cx).is_lang_item(cx, OptionNone))375}376377/// Checks if `arm` has the form `None => None`.378pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {379    is_none_pattern(cx, arm.pat)380        && matches!(381            peel_blocks(arm.body).kind,382            ExprKind::Path(qpath)383            if cx.qpath_res(&qpath, arm.body.hir_id).ctor_parent(cx).is_lang_item(cx, OptionNone)384        )385}386387/// Checks if the given `QPath` belongs to a type alias.388pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {389    match *qpath {390        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),391        QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath),392        QPath::TypeRelative(..) => false,393    }394}395396/// Checks if the `def_id` belongs to a function that is part of a trait impl.397pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {398    if let Node::Item(item) = cx.tcx.parent_hir_node(cx.tcx.local_def_id_to_hir_id(def_id))399        && let ItemKind::Impl(imp) = item.kind400    {401        imp.of_trait.is_some()402    } else {403        false404    }405}406407pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {408    match *path {409        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),410        QPath::TypeRelative(_, seg) => seg,411    }412}413414pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {415    last_path_segment(qpath)416        .args417        .map_or(&[][..], |a| a.args)418        .iter()419        .filter_map(|a| match a {420            GenericArg::Type(ty) => Some(ty.as_unambig_ty()),421            _ => None,422        })423}424425/// If the expression is a path to a local (with optional projections),426/// returns the canonical `HirId` of the local.427///428/// For example, `x.field[0].field2` would return the `HirId` of `x`.429pub fn path_to_local_with_projections(expr: &Expr<'_>) -> Option<HirId> {430    match expr.kind {431        ExprKind::Field(recv, _) | ExprKind::Index(recv, _, _) => path_to_local_with_projections(recv),432        ExprKind::Path(QPath::Resolved(433            _,434            Path {435                res: Res::Local(local), ..436            },437        )) => Some(*local),438        _ => None,439    }440}441442/// Gets the `hir::TraitRef` of the trait the given method is implemented for.443///444/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:445///446/// ```no_run447/// struct Point(isize, isize);448///449/// impl std::ops::Add for Point {450///     type Output = Self;451///452///     fn add(self, other: Self) -> Self {453///         Point(0, 0)454///     }455/// }456/// ```457pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {458    if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))459        && let ItemKind::Impl(impl_) = &item.kind460        && let Some(of_trait) = impl_.of_trait461    {462        return Some(&of_trait.trait_ref);463    }464    None465}466467/// This method will return tuple of projection stack and root of the expression,468/// used in `can_mut_borrow_both`.469///470/// For example, if `e` represents the `v[0].a.b[x]`471/// this method will return a tuple, composed of a `Vec`472/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`473/// and an `Expr` for root of them, `v`474fn projection_stack<'a, 'hir>(475    mut e: &'a Expr<'hir>,476    ctxt: SyntaxContext,477) -> Option<(Vec<&'a Expr<'hir>>, &'a Expr<'hir>)> {478    let mut result = vec![];479    let root = loop {480        match e.kind {481            ExprKind::Index(ep, _, _) | ExprKind::Field(ep, _) if e.span.ctxt() == ctxt => {482                result.push(e);483                e = ep;484            },485            ExprKind::Index(..) | ExprKind::Field(..) => return None,486            _ => break e,487        }488    };489    result.reverse();490    Some((result, root))491}492493/// Gets the mutability of the custom deref adjustment, if any.494pub fn expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability> {495    cx.typeck_results()496        .expr_adjustments(e)497        .iter()498        .find_map(|a| match a.kind {499            Adjust::Deref(DerefAdjustKind::Overloaded(d)) => Some(Some(d.mutbl)),500            Adjust::Deref(DerefAdjustKind::Builtin) => None,501            _ => Some(None),502        })503        .and_then(|x| x)504}505506/// Checks if two expressions can be mutably borrowed simultaneously507/// and they aren't dependent on borrowing same thing twice508pub fn can_mut_borrow_both(cx: &LateContext<'_>, ctxt: SyntaxContext, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {509    let Some((s1, r1)) = projection_stack(e1, ctxt) else {510        return false;511    };512    let Some((s2, r2)) = projection_stack(e2, ctxt) else {513        return false;514    };515    if !eq_expr_value(cx, ctxt, r1, r2) {516        return true;517    }518    if expr_custom_deref_adjustment(cx, r1).is_some() || expr_custom_deref_adjustment(cx, r2).is_some() {519        return false;520    }521522    for (x1, x2) in zip(&s1, &s2) {523        if expr_custom_deref_adjustment(cx, x1).is_some() || expr_custom_deref_adjustment(cx, x2).is_some() {524            return false;525        }526527        match (&x1.kind, &x2.kind) {528            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {529                if i1 != i2 {530                    return true;531                }532            },533            _ => return false,534        }535    }536    false537}538539/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"540/// constructor from the std library541fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {542    let std_types_symbols = &[543        sym::Vec,544        sym::VecDeque,545        sym::LinkedList,546        sym::HashMap,547        sym::BTreeMap,548        sym::HashSet,549        sym::BTreeSet,550        sym::BinaryHeap,551    ];552553    if let QPath::TypeRelative(_, method) = path554        && method.ident.name == sym::new555        && let Some(impl_did) = cx.tcx.impl_of_assoc(def_id)556        && let Some(adt) = cx557            .tcx558            .type_of(impl_did)559            .instantiate_identity()560            .skip_norm_wip()561            .ty_adt_def()562    {563        return Some(adt.did()) == cx.tcx.lang_items().string()564            || (cx.tcx.get_diagnostic_name(adt.did())).is_some_and(|adt_name| std_types_symbols.contains(&adt_name));565    }566    false567}568569/// Returns true if the expr is equal to `Default::default` when evaluated.570pub fn is_default_equivalent_call(571    cx: &LateContext<'_>,572    repl_func: &Expr<'_>,573    whole_call_expr: Option<&Expr<'_>>,574) -> bool {575    if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind576        && let Some(repl_def) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def(cx)577        && (repl_def.assoc_fn_parent(cx).is_diag_item(cx, sym::Default)578            || is_default_equivalent_ctor(cx, repl_def.1, repl_func_qpath))579    {580        return true;581    }582583    // Get the type of the whole method call expression, find the exact method definition, look at584    // its body and check if it is similar to the corresponding `Default::default()` body.585    let Some(e) = whole_call_expr else { return false };586    let Some(default_fn_def_id) = cx.tcx.get_diagnostic_item(sym::default_fn) else {587        return false;588    };589    let Some(ty) = cx.tcx.typeck(e.hir_id.owner.def_id).expr_ty_adjusted_opt(e) else {590        return false;591    };592    let args = rustc_ty::GenericArgs::for_item(cx.tcx, default_fn_def_id, |param, _| {593        if let rustc_ty::GenericParamDefKind::Lifetime = param.kind {594            cx.tcx.lifetimes.re_erased.into()595        } else if param.index == 0 && param.name == kw::SelfUpper {596            ty.into()597        } else {598            param.to_error(cx.tcx)599        }600    });601    let instance = rustc_ty::Instance::try_resolve(cx.tcx, cx.typing_env(), default_fn_def_id, args);602603    let Ok(Some(instance)) = instance else { return false };604    if let rustc_ty::InstanceKind::Item(def) = instance.def605        && !cx.tcx.is_mir_available(def)606    {607        return false;608    }609    let ExprKind::Path(ref repl_func_qpath) = repl_func.kind else {610        return false;611    };612    let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() else {613        return false;614    };615616    // Get the MIR Body for the `<Ty as Default>::default()` function.617    // If it is a value or call (either fn or ctor), we compare its `DefId` against the one for the618    // resolution of the expression we had in the path. This lets us identify, for example, that619    // the body of `<Vec<T> as Default>::default()` is a `Vec::new()`, and the field was being620    // initialized to `Vec::new()` as well.621    let body = cx.tcx.instance_mir(instance.def);622    for block_data in body.basic_blocks.iter() {623        if block_data.statements.len() == 1624            && let StatementKind::Assign(assign) = &block_data.statements[0].kind625            && assign.0.local == RETURN_PLACE626            && let Rvalue::Aggregate(kind, _places) = &assign.1627            && let AggregateKind::Adt(did, variant_index, _, _, _) = **kind628            && let def = cx.tcx.adt_def(did)629            && let variant = &def.variant(variant_index)630            && variant.fields.is_empty()631            && let Some((_, did)) = variant.ctor632            && did == repl_def_id633        {634            return true;635        } else if block_data.statements.is_empty()636            && let Some(term) = &block_data.terminator637        {638            match &term.kind {639                TerminatorKind::Call {640                    func: Operand::Constant(c),641                    ..642                } if let rustc_ty::FnDef(did, _args) = c.ty().kind()643                    && *did == repl_def_id =>644                {645                    return true;646                },647                TerminatorKind::TailCall {648                    func: Operand::Constant(c),649                    ..650                } if let rustc_ty::FnDef(did, _args) = c.ty().kind()651                    && *did == repl_def_id =>652                {653                    return true;654                },655                _ => {},656            }657        }658    }659    false660}661662/// Returns true if the expr is equal to `Default::default()` of its type when evaluated.663///664/// It doesn't cover all cases, like struct literals, but it is a close approximation.665pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {666    match &e.kind {667        ExprKind::Lit(lit) => match lit.node {668            LitKind::Bool(false) | LitKind::Int(Pu128(0), _) => true,669            LitKind::Str(s, _) => s.is_empty(),670            _ => false,671        },672        ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),673        ExprKind::Repeat(x, len) => {674            if let ConstArgKind::Anon(anon_const) = len.kind675                && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind676                && let LitKind::Int(v, _) = const_lit.node677                && v <= 32678                && is_default_equivalent(cx, x)679            {680                true681            } else {682                false683            }684        },685        ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func, Some(e)),686        ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg),687        ExprKind::Path(qpath) => cx688            .qpath_res(qpath, e.hir_id)689            .ctor_parent(cx)690            .is_lang_item(cx, OptionNone),691        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),692        ExprKind::Block(Block { stmts: [], expr, .. }, _) => expr.is_some_and(|e| is_default_equivalent(cx, e)),693        _ => false,694    }695}696697fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {698    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind699        && seg.ident.name == sym::from700    {701        match arg.kind {702            ExprKind::Lit(hir::Lit {703                node: LitKind::Str(sym, _),704                ..705            }) => return sym.is_empty() && ty.basic_res().is_lang_item(cx, LangItem::String),706            ExprKind::Array([]) => return ty.basic_res().is_diag_item(cx, sym::Vec),707            ExprKind::Repeat(_, len) => {708                if let ConstArgKind::Anon(anon_const) = len.kind709                    && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind710                    && let LitKind::Int(v, _) = const_lit.node711                {712                    return v == 0 && ty.basic_res().is_diag_item(cx, sym::Vec);713                }714            },715            _ => (),716        }717    }718    false719}720721/// Checks if the top level expression can be moved into a closure as is.722/// Currently checks for:723/// * Break/Continue outside the given loop HIR ids.724/// * Yield/Return statements.725/// * Inline assembly.726/// * Usages of a field of a local where the type of the local can be partially moved.727///728/// For example, given the following function:729///730/// ```no_run731/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {732///     for item in iter {733///         let s = item.1;734///         if item.0 > 10 {735///             continue;736///         } else {737///             s.clear();738///         }739///     }740/// }741/// ```742///743/// When called on the expression `item.0` this will return false unless the local `item` is in the744/// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it745/// isn't always safe to move into a closure when only a single field is needed.746///747/// When called on the `continue` expression this will return false unless the outer loop expression748/// is in the `loop_ids` set.749///750/// Note that this check is not recursive, so passing the `if` expression will always return true751/// even though sub-expressions might return false.752pub fn can_move_expr_to_closure_no_visit<'tcx>(753    cx: &LateContext<'tcx>,754    expr: &'tcx Expr<'_>,755    loop_ids: &[HirId],756    ignore_locals: &HirIdSet,757) -> bool {758    match expr.kind {759        ExprKind::Break(Destination { target_id: Ok(id), .. }, _)760        | ExprKind::Continue(Destination { target_id: Ok(id), .. })761            if loop_ids.contains(&id) =>762        {763            true764        },765        ExprKind::Break(..)766        | ExprKind::Continue(_)767        | ExprKind::Ret(_)768        | ExprKind::Yield(..)769        | ExprKind::InlineAsm(_) => false,770        // Accessing a field of a local value can only be done if the type isn't771        // partially moved.772        ExprKind::Field(773            &Expr {774                hir_id,775                kind:776                    ExprKind::Path(QPath::Resolved(777                        _,778                        Path {779                            res: Res::Local(local_id),780                            ..781                        },782                    )),783                ..784            },785            _,786        ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {787            // TODO: check if the local has been partially moved. Assume it has for now.788            false789        },790        _ => true,791    }792}793794/// How a local is captured by a closure795#[derive(Debug, Clone, Copy, PartialEq, Eq)]796pub enum CaptureKind {797    Value,798    Use,799    Ref(Mutability),800}801impl CaptureKind {802    pub fn is_imm_ref(self) -> bool {803        self == Self::Ref(Mutability::Not)804    }805}806impl std::ops::BitOr for CaptureKind {807    type Output = Self;808    fn bitor(self, rhs: Self) -> Self::Output {809        match (self, rhs) {810            (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,811            (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use,812            (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))813            | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),814            (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),815        }816    }817}818impl std::ops::BitOrAssign for CaptureKind {819    fn bitor_assign(&mut self, rhs: Self) {820        *self = *self | rhs;821    }822}823824/// Given an expression referencing a local, determines how it would be captured in a closure.825///826/// Note as this will walk up to parent expressions until the capture can be determined it should827/// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or828/// function argument (other than a receiver).829pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {830    fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {831        let mut capture = CaptureKind::Ref(Mutability::Not);832        pat.each_binding_or_first(&mut |_, id, span, _| match cx833            .typeck_results()834            .extract_binding_mode(cx.sess(), id, span)835            .0836        {837            ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => {838                capture = CaptureKind::Value;839            },840            ByRef::Yes(_, Mutability::Mut) if capture != CaptureKind::Value => {841                capture = CaptureKind::Ref(Mutability::Mut);842            },843            _ => (),844        });845        capture846    }847848    debug_assert!(matches!(849        e.kind,850        ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))851    ));852853    let mut capture = CaptureKind::Value;854    let mut capture_expr_ty = e;855856    for (parent, child_id) in hir_parent_with_src_iter(cx.tcx, e.hir_id) {857        if let [858            Adjustment {859                kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),860                target,861            },862            ref adjust @ ..,863        ] = *cx864            .typeck_results()865            .adjustments()866            .get(child_id)867            .map_or(&[][..], |x| &**x)868            && let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) =869                *adjust.last().map_or(target, |a| a.target).kind()870        {871            return CaptureKind::Ref(mutability);872        }873874        match parent {875            Node::Expr(e) => match e.kind {876                ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),877                ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),878                ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {879                    return CaptureKind::Ref(Mutability::Mut);880                },881                ExprKind::Field(..) => {882                    if capture == CaptureKind::Value {883                        capture_expr_ty = e;884                    }885                },886                ExprKind::Let(let_expr) => {887                    let mutability = match pat_capture_kind(cx, let_expr.pat) {888                        CaptureKind::Value | CaptureKind::Use => Mutability::Not,889                        CaptureKind::Ref(m) => m,890                    };891                    return CaptureKind::Ref(mutability);892                },893                ExprKind::Match(_, arms, _) => {894                    let mut mutability = Mutability::Not;895                    for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {896                        match capture {897                            CaptureKind::Value | CaptureKind::Use => break,898                            CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,899                            CaptureKind::Ref(Mutability::Not) => (),900                        }901                    }902                    return CaptureKind::Ref(mutability);903                },904                _ => break,905            },906            Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) {907                CaptureKind::Value | CaptureKind::Use => break,908                capture @ CaptureKind::Ref(_) => return capture,909            },910            _ => break,911        }912    }913914    if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {915        // Copy types are never automatically captured by value.916        CaptureKind::Ref(Mutability::Not)917    } else {918        capture919    }920}921922/// Checks if the expression can be moved into a closure as is. This will return a list of captures923/// if so, otherwise, `None`.924pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {925    struct V<'cx, 'tcx> {926        cx: &'cx LateContext<'tcx>,927        // Stack of potential break targets contained in the expression.928        loops: Vec<HirId>,929        /// Local variables created in the expression. These don't need to be captured.930        locals: HirIdSet,931        /// Whether this expression can be turned into a closure.932        allow_closure: bool,933        /// Locals which need to be captured, and whether they need to be by value, reference, or934        /// mutable reference.935        captures: HirIdMap<CaptureKind>,936    }937    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {938        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {939            if !self.allow_closure {940                return;941            }942943            match e.kind {944                ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {945                    if !self.locals.contains(&l) {946                        let cap = capture_local_usage(self.cx, e);947                        self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);948                    }949                },950                ExprKind::Closure(closure) => {951                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) {952                        let local_id = match capture.place.base {953                            PlaceBase::Local(id) => id,954                            PlaceBase::Upvar(var) => var.var_path.hir_id,955                            _ => continue,956                        };957                        if !self.locals.contains(&local_id) {958                            let capture = match capture.info.capture_kind {959                                UpvarCapture::ByValue => CaptureKind::Value,960                                UpvarCapture::ByUse => CaptureKind::Use,961                                UpvarCapture::ByRef(kind) => match kind {962                                    BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not),963                                    BorrowKind::UniqueImmutable | BorrowKind::Mutable => {964                                        CaptureKind::Ref(Mutability::Mut)965                                    },966                                },967                            };968                            self.captures969                                .entry(local_id)970                                .and_modify(|e| *e |= capture)971                                .or_insert(capture);972                        }973                    }974                },975                ExprKind::Loop(b, ..) => {976                    self.loops.push(e.hir_id);977                    self.visit_block(b);978                    self.loops.pop();979                },980                _ => {981                    self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);982                    walk_expr(self, e);983                },984            }985        }986987        fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {988            p.each_binding_or_first(&mut |_, id, _, _| {989                self.locals.insert(id);990            });991        }992    }993994    let mut v = V {995        cx,996        loops: Vec::new(),997        locals: HirIdSet::default(),998        allow_closure: true,999        captures: HirIdMap::default(),1000    };1001    v.visit_expr(expr);1002    v.allow_closure.then_some(v.captures)1003}10041005/// Arguments of a method: the receiver and all the additional arguments.1006pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;10071008/// Returns the method names and argument list of nested method call expressions that make up1009/// `expr`. method/span lists are sorted with the most recent call first.1010pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {1011    let mut method_names = Vec::with_capacity(max_depth);1012    let mut arg_lists = Vec::with_capacity(max_depth);1013    let mut spans = Vec::with_capacity(max_depth);10141015    let mut current = expr;1016    for _ in 0..max_depth {1017        if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {1018            if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {1019                break;1020            }1021            method_names.push(path.ident.name);1022            arg_lists.push((*receiver, &**args));1023            spans.push(path.ident.span);1024            current = receiver;1025        } else {1026            break;1027        }1028    }10291030    (method_names, arg_lists, spans)1031}10321033/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.1034///1035/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,1036/// `method_chain_args(expr, &[sym::bar, sym::baz])` will return a `Vec`1037/// containing the `Expr`s for1038/// `.bar()` and `.baz()`1039pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {1040    let mut current = expr;1041    let mut matched = Vec::with_capacity(methods.len());1042    for method_name in methods.iter().rev() {1043        // method chains are stored last -> first1044        if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {1045            if path.ident.name == *method_name {1046                if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {1047                    return None;1048                }1049                matched.push((receiver, args)); // build up `matched` backwards1050                current = receiver; // go to parent expression1051            } else {1052                return None;1053            }1054        } else {1055            return None;1056        }1057    }1058    // Reverse `matched` so that it is in the same order as `methods`.1059    matched.reverse();1060    Some(matched)1061}10621063/// Returns `true` if the provided `def_id` is an entrypoint to a program.1064pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {1065    cx.tcx1066        .entry_fn(())1067        .is_some_and(|(entry_fn_def_id, _)| def_id == entry_fn_def_id)1068}10691070/// Returns `true` if the expression is in the program's `#[panic_handler]`.1071pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {1072    let parent = cx.tcx.hir_get_parent_item(e.hir_id);1073    Some(parent.to_def_id()) == cx.tcx.lang_items().panic_impl()1074}10751076/// Gets the name of the item the expression is in, if available.1077pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {1078    let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id;1079    match cx.tcx.hir_node_by_def_id(parent_id) {1080        Node::Item(item) => item.kind.ident().map(|ident| ident.name),1081        Node::TraitItem(TraitItem { ident, .. }) | Node::ImplItem(ImplItem { ident, .. }) => Some(ident.name),1082        _ => None,1083    }1084}10851086pub struct ContainsName<'a, 'tcx> {1087    pub cx: &'a LateContext<'tcx>,1088    pub name: Symbol,1089}10901091impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {1092    type Result = ControlFlow<()>;1093    type NestedFilter = nested_filter::OnlyBodies;10941095    fn visit_name(&mut self, name: Symbol) -> Self::Result {1096        if self.name == name {1097            ControlFlow::Break(())1098        } else {1099            ControlFlow::Continue(())1100        }1101    }11021103    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {1104        self.cx.tcx1105    }1106}11071108/// Checks if an `Expr` contains a certain name.1109pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {1110    let mut cn = ContainsName { cx, name };1111    cn.visit_expr(expr).is_break()1112}11131114/// Returns `true` if `expr` contains a return expression1115pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {1116    for_each_expr_without_closures(expr, |e| {1117        if matches!(e.kind, ExprKind::Ret(..)) {1118            ControlFlow::Break(())1119        } else {1120            ControlFlow::Continue(())1121        }1122    })1123    .is_some()1124}11251126/// Gets the parent expression, if any –- this is useful to constrain a lint.1127pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {1128    get_parent_expr_for_hir(cx, e.hir_id)1129}11301131/// This retrieves the parent for the given `HirId` if it's an expression. This is useful for1132/// constraint lints1133pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {1134    match cx.tcx.parent_hir_node(hir_id) {1135        Node::Expr(parent) => Some(parent),1136        _ => None,1137    }1138}11391140/// Gets the enclosing block, if any.1141pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {1142    let enclosing_node = cx1143        .tcx1144        .hir_get_enclosing_scope(hir_id)1145        .map(|enclosing_id| cx.tcx.hir_node(enclosing_id));1146    enclosing_node.and_then(|node| match node {1147        Node::Block(block) => Some(block),1148        Node::Item(&Item {1149            kind: ItemKind::Fn { body: eid, .. },1150            ..1151        })1152        | Node::ImplItem(&ImplItem {1153            kind: ImplItemKind::Fn(_, eid),1154            ..1155        })1156        | Node::TraitItem(&TraitItem {1157            kind: TraitItemKind::Fn(_, TraitFn::Provided(eid)),1158            ..1159        }) => match cx.tcx.hir_body(eid).value.kind {1160            ExprKind::Block(block, _) => Some(block),1161            _ => None,1162        },1163        _ => None,1164    })1165}11661167/// Returns the [`Closure`] enclosing `hir_id`, if any.1168pub fn get_enclosing_closure<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Closure<'tcx>> {1169    cx.tcx.hir_parent_iter(hir_id).find_map(|(_, node)| {1170        if let Node::Expr(expr) = node1171            && let ExprKind::Closure(closure) = expr.kind1172        {1173            Some(closure)1174        } else {1175            None1176        }1177    })1178}11791180/// Checks whether a local identified by `local_id` is captured as an upvar by the given `closure`.1181pub fn is_upvar_in_closure(cx: &LateContext<'_>, closure: &Closure<'_>, local_id: HirId) -> bool {1182    cx.typeck_results()1183        .closure_min_captures1184        .get(&closure.def_id)1185        .is_some_and(|x| x.contains_key(&local_id))1186}11871188/// Gets the loop or closure enclosing the given expression, if any.1189pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(1190    cx: &LateContext<'tcx>,1191    expr: &Expr<'_>,1192) -> Option<&'tcx Expr<'tcx>> {1193    for (_, node) in cx.tcx.hir_parent_iter(expr.hir_id) {1194        match node {1195            Node::Expr(e) => match e.kind {1196                ExprKind::Closure { .. }1197                    if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()1198                        && subs.as_closure().kind() == ClosureKind::FnOnce => {},11991200                // Note: A closure's kind is determined by how it's used, not it's captures.1201                ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),1202                _ => (),1203            },1204            Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) | Node::ExprField(_) => (),1205            _ => break,1206        }1207    }1208    None1209}12101211/// Gets the parent node if it's an impl block.1212pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {1213    match tcx.hir_parent_iter(id).next() {1214        Some((1215            _,1216            Node::Item(Item {1217                kind: ItemKind::Impl(imp),1218                ..1219            }),1220        )) => Some(imp),1221        _ => None,1222    }1223}12241225/// Removes blocks around an expression, only if the block contains just one expression1226/// and no statements. Unsafe blocks are not removed.1227///1228/// Examples:1229///  * `{}`               -> `{}`1230///  * `{ x }`            -> `x`1231///  * `{{ x }}`          -> `x`1232///  * `{ x; }`           -> `{ x; }`1233///  * `{ x; y }`         -> `{ x; y }`1234///  * `{ unsafe { x } }` -> `unsafe { x }`1235pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {1236    while let ExprKind::Block(1237        Block {1238            stmts: [],1239            expr: Some(inner),1240            rules: BlockCheckMode::DefaultBlock,1241            ..1242        },1243        _,1244    ) = expr.kind1245    {1246        expr = inner;1247    }1248    expr1249}12501251/// Removes blocks around an expression, only if the block contains just one expression1252/// or just one expression statement with a semicolon. Unsafe blocks are not removed.1253///1254/// Examples:1255///  * `{}`               -> `{}`1256///  * `{ x }`            -> `x`1257///  * `{ x; }`           -> `x`1258///  * `{{ x; }}`         -> `x`1259///  * `{ x; y }`         -> `{ x; y }`1260///  * `{ unsafe { x } }` -> `unsafe { x }`1261pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {1262    while let ExprKind::Block(1263        Block {1264            stmts: [],1265            expr: Some(inner),1266            rules: BlockCheckMode::DefaultBlock,1267            ..1268        }1269        | Block {1270            stmts:1271                [1272                    Stmt {1273                        kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),1274                        ..1275                    },1276                ],1277            expr: None,1278            rules: BlockCheckMode::DefaultBlock,1279            ..1280        },1281        _,1282    ) = expr.kind1283    {1284        expr = inner;1285    }1286    expr1287}12881289/// Checks if the given expression is the else clause of either an `if` or `if let` expression.1290pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {1291    let mut iter = tcx.hir_parent_iter(expr.hir_id);1292    match iter.next() {1293        Some((1294            _,1295            Node::Expr(Expr {1296                kind: ExprKind::If(_, _, Some(else_expr)),1297                ..1298            }),1299        )) => else_expr.hir_id == expr.hir_id,1300        _ => false,1301    }1302}13031304/// Checks if the given expression is a part of `let else`1305/// returns `true` for both the `init` and the `else` part1306pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {1307    hir_parent_with_src_iter(tcx, expr.hir_id).any(|(node, child_id)| {1308        matches!(1309            node,1310            Node::LetStmt(LetStmt {1311                init: Some(init),1312                els: Some(els),1313                ..1314            })1315            if init.hir_id == child_id || els.hir_id == child_id1316        )1317    })1318}13191320/// Checks if the given expression is the else clause of a `let else` expression1321pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {1322    hir_parent_with_src_iter(tcx, expr.hir_id).any(|(node, child_id)| {1323        matches!(1324            node,1325            Node::LetStmt(LetStmt { els: Some(els), .. })1326            if els.hir_id == child_id1327        )1328    })1329}13301331/// Checks whether the given `Expr` is a range over the entire container.1332pub fn is_full_collection_range(cx: &LateContext<'_>, container: Option<HirId>, expr: &Expr<'_>) -> bool {1333    if let Some(Range { start, end, ty, .. }) = Range::hir(cx, expr) {1334        start.is_none_or(|start| is_integer_literal(start, 0))1335            && end.is_none_or(|end| {1336                if ty.limits() == RangeLimits::HalfOpen1337                    && let Some(container) = container1338                    && let ExprKind::MethodCall(seg, recv, [], _) = end.kind1339                {1340                    seg.ident.name == sym::len && recv.res_local_id() == Some(container)1341                } else {1342                    false1343                }1344            })1345    } else {1346        false1347    }1348}13491350/// Checks whether the given expression is a constant literal of the given value.1351pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {1352    if let ExprKind::Lit(spanned) = expr.kind1353        && let LitKind::Int(v, _) = spanned.node1354    {1355        return v == value;1356    }1357    false1358}13591360/// Checks whether the given expression is an untyped integer literal.1361pub fn is_integer_literal_untyped(expr: &Expr<'_>) -> bool {1362    if let ExprKind::Lit(spanned) = expr.kind1363        && let LitKind::Int(_, suffix) = spanned.node1364    {1365        return suffix == LitIntType::Unsuffixed;1366    }13671368    false1369}13701371/// Checks whether the given expression is a constant literal of the given value.1372pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool {1373    if let ExprKind::Lit(spanned) = expr.kind1374        && let LitKind::Float(v, _) = spanned.node1375    {1376        v.as_str().parse() == Ok(value)1377    } else {1378        false1379    }1380}13811382/// Returns `true` if the given `Expr` has been coerced before.1383///1384/// Examples of coercions can be found in the Nomicon at1385/// <https://doc.rust-lang.org/nomicon/coercions.html>.1386///1387/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::check::coercion` for1388/// more information on adjustments and coercions.1389pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {1390    cx.typeck_results().adjustments().get(e.hir_id).is_some()1391}13921393/// Returns the pre-expansion span if this comes from an expansion of the1394/// macro `name`.1395/// See also [`is_direct_expn_of`].1396#[must_use]1397pub fn is_expn_of(mut span: Span, name: Symbol) -> Option<Span> {1398    loop {1399        if span.from_expansion() {1400            let data = span.ctxt().outer_expn_data();1401            let new_span = data.call_site;14021403            if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind1404                && mac_name == name1405            {1406                return Some(new_span);1407            }14081409            span = new_span;1410        } else {1411            return None;1412        }1413    }1414}14151416/// Returns the pre-expansion span if the span directly comes from an expansion1417/// of the macro `name`.1418/// The difference with [`is_expn_of`] is that in1419/// ```no_run1420/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }1421/// # macro_rules! bar { ($e:expr) => { $e } }1422/// foo!(bar!(42));1423/// ```1424/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only1425/// from `bar!` by `is_direct_expn_of`.1426#[must_use]1427pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option<Span> {1428    if span.from_expansion() {1429        let data = span.ctxt().outer_expn_data();1430        let new_span = data.call_site;14311432        if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind1433            && mac_name == name1434        {1435            return Some(new_span);1436        }1437    }14381439    None1440}14411442/// Convenience function to get the return type of a function.1443pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId) -> Ty<'tcx> {1444    let ret_ty = cx.tcx.fn_sig(fn_def_id).instantiate_identity().skip_norm_wip().output();1445    cx.tcx.instantiate_bound_regions_with_erased(ret_ty)1446}14471448/// Convenience function to get the nth argument type of a function.1449pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId, nth: usize) -> Ty<'tcx> {1450    let arg = cx1451        .tcx1452        .fn_sig(fn_def_id)1453        .instantiate_identity()1454        .skip_norm_wip()1455        .input(nth);1456    cx.tcx.instantiate_bound_regions_with_erased(arg)1457}14581459/// Checks if an expression is constructing a tuple-like enum variant or struct1460pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {1461    if let ExprKind::Call(fun, _) = expr.kind1462        && let ExprKind::Path(ref qp) = fun.kind1463    {1464        let res = cx.qpath_res(qp, fun.hir_id);1465        return match res {1466            Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,1467            Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),1468            _ => false,1469        };1470    }1471    false1472}14731474/// Returns `true` if a pattern is refutable.1475// TODO: should be implemented using rustc/mir_build/thir machinery1476pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {1477    fn is_qpath_refutable(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {1478        !matches!(1479            cx.qpath_res(qpath, id),1480            Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), _)1481        )1482    }14831484    fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {1485        i.into_iter().any(|pat| is_refutable(cx, pat))1486    }14871488    match pat.kind {1489        PatKind::Missing => unreachable!(),1490        PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.1491        PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),1492        PatKind::Ref(pat, _, _) => is_refutable(cx, pat),1493        PatKind::Expr(PatExpr {1494            kind: PatExprKind::Path(qpath),1495            hir_id,1496            ..1497        }) => is_qpath_refutable(cx, qpath, *hir_id),1498        PatKind::Or(pats) => {1499            // TODO: should be the honest check, that pats is exhaustive set1500            are_refutable(cx, pats)1501        },1502        PatKind::Tuple(pats, _) => are_refutable(cx, pats),1503        PatKind::Struct(ref qpath, fields, _) => {1504            is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))1505        },1506        PatKind::TupleStruct(ref qpath, pats, _) => {1507            is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, pats)1508        },1509        PatKind::Slice(head, middle, tail) => {1510            match &cx.typeck_results().node_type(pat.hir_id).kind() {1511                rustc_ty::Slice(..) => {1512                    // [..] is the only irrefutable slice pattern.1513                    !head.is_empty() || middle.is_none() || !tail.is_empty()1514                },1515                rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),1516                _ => {1517                    // unreachable!()1518                    true1519                },1520            }1521        },1522        PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,1523    }1524}15251526/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call1527/// the function once on the given pattern.1528pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {1529    if let PatKind::Or(pats) = pat.kind {1530        pats.iter().for_each(f);1531    } else {1532        f(pat);1533    }1534}15351536pub fn is_self(slf: &Param<'_>) -> bool {1537    if let PatKind::Binding(.., name, _) = slf.pat.kind {1538        name.name == kw::SelfLower1539    } else {1540        false1541    }1542}15431544pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {1545    if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind1546        && let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res1547    {1548        return true;1549    }1550    false1551}15521553pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {1554    (0..decl.inputs.len()).map(move |i| &body.params[i])1555}15561557/// Checks if a given expression is a match expression expanded from the `?`1558/// operator or the `try` macro.1559pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {1560    fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {1561        if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind1562            && ddpos.as_opt_usize().is_none()1563            && cx1564                .qpath_res(path, arm.pat.hir_id)1565                .ctor_parent(cx)1566                .is_lang_item(cx, ResultOk)1567            && let PatKind::Binding(_, hir_id, _, None) = pat[0].kind1568            && arm.body.res_local_id() == Some(hir_id)1569        {1570            return true;1571        }1572        false1573    }15741575    fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {1576        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {1577            cx.qpath_res(path, arm.pat.hir_id)1578                .ctor_parent(cx)1579                .is_lang_item(cx, ResultErr)1580        } else {1581            false1582        }1583    }15841585    if let ExprKind::Match(_, arms, ref source) = expr.kind {1586        // desugared from a `?` operator1587        if let MatchSource::TryDesugar(_) = *source {1588            return Some(expr);1589        }15901591        if arms.len() == 21592            && arms[0].guard.is_none()1593            && arms[1].guard.is_none()1594            && ((is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0])))1595        {1596            return Some(expr);1597        }1598    }15991600    None1601}16021603/// Returns `true` if the lint is `#[allow]`ed or `#[expect]`ed at any of the `ids`, fulfilling all1604/// of the expectations in `ids`1605///1606/// This should only be used when the lint would otherwise be emitted, for a way to check if a lint1607/// is allowed early to skip work see [`is_lint_allowed`]1608///1609/// To emit at a lint at a different context than the one current see1610/// [`span_lint_hir`](diagnostics::span_lint_hir) or1611/// [`span_lint_hir_and_then`](diagnostics::span_lint_hir_and_then)1612pub fn fulfill_or_allowed(cx: &LateContext<'_>, lint: &'static Lint, ids: impl IntoIterator<Item = HirId>) -> bool {1613    let mut suppress_lint = false;16141615    for id in ids {1616        let level_spec = cx.tcx.lint_level_spec_at_node(lint, id);1617        if let Some(expectation) = level_spec.lint_id() {1618            cx.fulfill_expectation(expectation);1619        }16201621        match level_spec.level() {1622            Level::Allow | Level::Expect => suppress_lint = true,1623            Level::Warn | Level::ForceWarn | Level::Deny | Level::Forbid => {},1624        }1625    }16261627    suppress_lint1628}16291630/// Returns `true` if the lint is allowed in the current context. This is useful for1631/// skipping long running code when it's unnecessary1632///1633/// This function should check the lint level for the same node, that the lint will1634/// be emitted at. If the information is buffered to be emitted at a later point, please1635/// make sure to use `span_lint_hir` functions to emit the lint. This ensures that1636/// expectations at the checked nodes will be fulfilled.1637pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {1638    cx.tcx.lint_level_spec_at_node(lint, id).is_allow()1639}16401641pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {1642    while let PatKind::Ref(subpat, _, _) = pat.kind {1643        pat = subpat;1644    }1645    pat1646}16471648pub fn int_bits(tcx: TyCtxt<'_>, ity: IntTy) -> u64 {1649    Integer::from_int_ty(&tcx, ity).size().bits()1650}16511652#[expect(clippy::cast_possible_wrap)]1653/// Turn a constant int byte representation into an i1281654pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: IntTy) -> i128 {1655    let amt = 128 - int_bits(tcx, ity);1656    ((u as i128) << amt) >> amt1657}16581659#[expect(clippy::cast_sign_loss)]1660/// clip unused bytes1661pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: IntTy) -> u128 {1662    let amt = 128 - int_bits(tcx, ity);1663    ((u as u128) << amt) >> amt1664}16651666/// clip unused bytes1667pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: UintTy) -> u128 {1668    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();1669    let amt = 128 - bits;1670    (u << amt) >> amt1671}16721673pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool {1674    attrs.iter().any(|attr| attr.has_name(symbol))1675}16761677pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {1678    find_attr!(cx.tcx, hir_id, Repr { .. })1679}16801681pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {1682    let mut prev_enclosing_node = None;1683    let mut enclosing_node = node;1684    while Some(enclosing_node) != prev_enclosing_node {1685        if has_attr(tcx.hir_attrs(enclosing_node), symbol) {1686            return true;1687        }1688        prev_enclosing_node = Some(enclosing_node);1689        enclosing_node = tcx.hir_get_parent_item(enclosing_node).into();1690    }16911692    false1693}16941695/// Checks if the given HIR node is inside an `impl` block with the `automatically_derived`1696/// attribute.1697pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {1698    tcx.hir_parent_owner_iter(id)1699        .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_))))1700        .any(|(id, _)| find_attr!(tcx, id.def_id, AutomaticallyDerived))1701}17021703/// Checks if the given `DefId` matches the `libc` item.1704pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool {1705    // libc is meant to be used as a flat list of names, but they're all actually defined in different1706    // modules based on the target platform. Ignore everything but crate name and the item name.1707    cx.tcx.crate_name(did.krate) == sym::libc && cx.tcx.def_path_str(did).ends_with(name.as_str())1708}17091710/// Returns the list of condition expressions and the list of blocks in a1711/// sequence of `if/else`.1712/// E.g., this returns `([a, b], [c, d, e])` for the expression1713/// `if a { c } else if b { d } else { e }`.1714pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {1715    let mut conds = Vec::new();1716    let mut blocks: Vec<&Block<'_>> = Vec::new();17171718    while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {1719        conds.push(cond);1720        if let ExprKind::Block(block, _) = then.kind {1721            blocks.push(block);1722        } else {1723            panic!("ExprKind::If node is not an ExprKind::Block");1724        }17251726        if let Some(else_expr) = r#else {1727            expr = else_expr;1728        } else {1729            break;1730        }1731    }17321733    // final `else {..}`1734    if !blocks.is_empty()1735        && let ExprKind::Block(block, _) = expr.kind1736    {1737        blocks.push(block);1738    }17391740    (conds, blocks)1741}17421743/// Peels away all the compiler generated code surrounding the body of an async closure.1744pub fn get_async_closure_expr<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {1745    if let ExprKind::Closure(&Closure {1746        body,1747        kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),1748        ..1749    }) = expr.kind1750        && let ExprKind::Block(1751            Block {1752                expr:1753                    Some(Expr {1754                        kind: ExprKind::DropTemps(inner_expr),1755                        ..1756                    }),1757                ..1758            },1759            _,1760        ) = tcx.hir_body(body).value.kind1761    {1762        Some(inner_expr)1763    } else {1764        None1765    }1766}17671768/// Peels away all the compiler generated code surrounding the body of an async function,1769pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {1770    get_async_closure_expr(tcx, body.value)1771}17721773// check if expr is calling method or function with #[must_use] attribute1774pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {1775    let did = match expr.kind {1776        ExprKind::Call(path, _) => {1777            if let ExprKind::Path(ref qpath) = path.kind1778                && let Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id)1779            {1780                Some(did)1781            } else {1782                None1783            }1784        },1785        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),1786        _ => None,1787    };17881789    did.is_some_and(|did| find_attr!(cx.tcx, did, MustUse { .. }))1790}17911792/// Checks if a function's body represents the identity function. Looks for bodies of the form:1793/// * `|x| x`1794/// * `|x| return x`1795/// * `|x| { return x }`1796/// * `|x| { return x; }`1797/// * `|(x, y)| (x, y)`1798/// * `|[x, y]| [x, y]`1799/// * `|Foo(bar, baz)| Foo(bar, baz)`1800/// * `|Foo { bar, baz }| Foo { bar, baz }`1801/// * `|x| { let y = x; ...; let z = y; z }`1802/// * `|x| { let y = x; ...; let z = y; return z }`1803///1804/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.1805fn is_body_identity_function<'hir>(cx: &LateContext<'_>, func: &Body<'hir>) -> bool {1806    let [param] = func.params else {1807        return false;1808    };18091810    let mut param_pat = param.pat;18111812    // Given a sequence of `Stmt`s of the form `let p = e` where `e` is an expr identical to the1813    // current `param_pat`, advance the current `param_pat` to `p`.1814    //1815    // Note: This is similar to `clippy_utils::get_last_chain_binding_hir_id`, but it works1816    // directly over a `Pattern` rather than a `HirId`. And it checks for compatibility via1817    // `is_expr_identity_of_pat` rather than `HirId` equality1818    let mut advance_param_pat_over_stmts = |stmts: &[Stmt<'hir>]| {1819        for stmt in stmts {1820            if let StmtKind::Let(local) = stmt.kind1821                && let Some(init) = local.init1822                && is_expr_identity_of_pat(cx, param_pat, init, true)1823            {1824                param_pat = local.pat;1825            } else {1826                return false;1827            }1828        }18291830        true1831    };18321833    let mut expr = func.value;1834    loop {1835        match expr.kind {1836            ExprKind::Block(1837                &Block {1838                    stmts: [],1839                    expr: Some(e),1840                    ..1841                },1842                _,1843            )1844            | ExprKind::Ret(Some(e)) => expr = e,1845            ExprKind::Block(1846                &Block {1847                    stmts: [stmt],1848                    expr: None,1849                    ..1850                },1851                _,1852            ) => {1853                if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind1854                    && let ExprKind::Ret(Some(ret_val)) = e.kind1855                {1856                    expr = ret_val;1857                } else {1858                    return false;1859                }1860            },1861            ExprKind::Block(1862                &Block {1863                    stmts, expr: Some(e), ..1864                },1865                _,1866            ) => {1867                if !advance_param_pat_over_stmts(stmts) {1868                    return false;1869                }18701871                expr = e;1872            },1873            ExprKind::Block(&Block { stmts, expr: None, .. }, _) => {1874                if let Some((last_stmt, stmts)) = stmts.split_last()1875                    && advance_param_pat_over_stmts(stmts)1876                    && let StmtKind::Semi(e) | StmtKind::Expr(e) = last_stmt.kind1877                    && let ExprKind::Ret(Some(ret_val)) = e.kind1878                {1879                    expr = ret_val;1880                } else {1881                    return false;1882                }1883            },1884            _ => return is_expr_identity_of_pat(cx, param_pat, expr, true),1885        }1886    }1887}18881889/// Checks if the given expression is an identity representation of the given pattern:1890/// * `x` is the identity representation of `x`1891/// * `(x, y)` is the identity representation of `(x, y)`1892/// * `[x, y]` is the identity representation of `[x, y]`1893/// * `Foo(bar, baz)` is the identity representation of `Foo(bar, baz)`1894/// * `Foo { bar, baz }` is the identity representation of `Foo { bar, baz }`1895///1896/// Note that `by_hir` is used to determine bindings are checked by their `HirId` or by their name.1897/// This can be useful when checking patterns in `let` bindings or `match` arms.1898pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>, by_hir: bool) -> bool {1899    if cx1900        .typeck_results()1901        .pat_binding_modes()1902        .get(pat.hir_id)1903        .is_some_and(|mode| matches!(mode.0, ByRef::Yes(..)))1904    {1905        // If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then1906        // due to match ergonomics, the inner patterns become references. Don't consider this1907        // the identity function as that changes types.1908        return false;1909    }19101911    // NOTE: we're inside a (function) body, so this won't ICE1912    let qpath_res = |qpath, hir| cx.typeck_results().qpath_res(qpath, hir);19131914    match (pat.kind, expr.kind) {1915        (PatKind::Binding(_, id, _, _), _) if by_hir => {1916            expr.res_local_id() == Some(id) && cx.typeck_results().expr_adjustments(expr).is_empty()1917        },1918        (PatKind::Binding(_, _, ident, _), ExprKind::Path(QPath::Resolved(_, path))) => {1919            matches!(path.segments, [ segment] if segment.ident.name == ident.name)1920        },1921        (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup))1922            if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() =>1923        {1924            over(pats, tup, |pat, expr| is_expr_identity_of_pat(cx, pat, expr, by_hir))1925        },1926        (PatKind::Slice(before, None, after), ExprKind::Array(arr)) if before.len() + after.len() == arr.len() => {1927            zip(before.iter().chain(after), arr).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr, by_hir))1928        },1929        (PatKind::TupleStruct(pat_ident, field_pats, dotdot), ExprKind::Call(ident, fields))1930            if dotdot.as_opt_usize().is_none() && field_pats.len() == fields.len() =>1931        {1932            // check ident1933            if let ExprKind::Path(ident) = &ident.kind1934                && qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id)1935                // check fields1936                && over(field_pats, fields, |pat, expr| is_expr_identity_of_pat(cx, pat, expr,by_hir))1937            {1938                true1939            } else {1940                false1941            }1942        },1943        (PatKind::Struct(pat_ident, field_pats, None), ExprKind::Struct(ident, fields, hir::StructTailExpr::None))1944            if field_pats.len() == fields.len() =>1945        {1946            // check ident1947            qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id)1948                // check fields1949                && unordered_over(field_pats, fields, |field_pat, field| {1950                    field_pat.ident == field.ident && is_expr_identity_of_pat(cx, field_pat.pat, field.expr, by_hir)1951                })1952        },1953        _ => false,1954    }1955}19561957/// This is the same as [`is_expr_identity_function`], but does not consider closures1958/// with type annotations for its bindings (or similar) as identity functions:1959/// * `|x: u8| x`1960/// * `std::convert::identity::<u8>`1961pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {1962    match expr.kind {1963        ExprKind::Closure(&Closure { body, fn_decl, .. })1964            if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(()))) =>1965        {1966            is_body_identity_function(cx, cx.tcx.hir_body(body))1967        },1968        ExprKind::Path(QPath::Resolved(_, path))1969            if path.segments.iter().all(|seg| seg.infer_args)1970                && let Some(did) = path.res.opt_def_id() =>1971        {1972            cx.tcx.is_diagnostic_item(sym::convert_identity, did)1973        },1974        _ => false,1975    }1976}19771978/// Checks if an expression represents the identity function1979/// Only examines closures and `std::convert::identity`1980///1981/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want1982/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't1983/// have type annotations. This is important because removing a closure with bindings can1984/// remove type information that helped type inference before, which can then lead to compile1985/// errors.1986pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {1987    match expr.kind {1988        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir_body(body)),1989        _ => expr.basic_res().is_diag_item(cx, sym::convert_identity),1990    }1991}19921993/// Gets the node where an expression is either used, or it's type is unified with another branch.1994/// Returns both the node and the `HirId` of the closest child node.1995pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {1996    for (node, child_id) in hir_parent_with_src_iter(tcx, expr.hir_id) {1997        match node {1998            Node::Block(_) => {},1999            Node::Arm(arm) if arm.body.hir_id == child_id => {},2000            Node::Expr(expr) => match expr.kind {

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.