clippy_utils/
lib.rs

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