Thanks to visit codestin.com
Credit goes to doc.rust-lang.org

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