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    cx.tcx
2137        .hir_attrs(hir::CRATE_HIR_ID)
2138        .iter()
2139        .any(|attr| attr.has_name(sym::no_std))
2140}
2141
2142pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
2143    cx.tcx
2144        .hir_attrs(hir::CRATE_HIR_ID)
2145        .iter()
2146        .any(|attr| attr.has_name(sym::no_core))
2147}
2148
2149/// Check if parent of a hir node is a trait implementation block.
2150/// For example, `f` in
2151/// ```no_run
2152/// # struct S;
2153/// # trait Trait { fn f(); }
2154/// impl Trait for S {
2155///     fn f() {}
2156/// }
2157/// ```
2158pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
2159    if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
2160        matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. }))
2161    } else {
2162        false
2163    }
2164}
2165
2166/// Check if it's even possible to satisfy the `where` clause for the item.
2167///
2168/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
2169///
2170/// ```ignore
2171/// fn foo() where i32: Iterator {
2172///     for _ in 2i32 {}
2173/// }
2174/// ```
2175pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
2176    use rustc_trait_selection::traits;
2177    let predicates = cx
2178        .tcx
2179        .predicates_of(did)
2180        .predicates
2181        .iter()
2182        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
2183    traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
2184}
2185
2186/// Returns the `DefId` of the callee if the given expression is a function or method call.
2187pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
2188    fn_def_id_with_node_args(cx, expr).map(|(did, _)| did)
2189}
2190
2191/// Returns the `DefId` of the callee if the given expression is a function or method call,
2192/// as well as its node args.
2193pub fn fn_def_id_with_node_args<'tcx>(
2194    cx: &LateContext<'tcx>,
2195    expr: &Expr<'_>,
2196) -> Option<(DefId, GenericArgsRef<'tcx>)> {
2197    let typeck = cx.typeck_results();
2198    match &expr.kind {
2199        ExprKind::MethodCall(..) => Some((
2200            typeck.type_dependent_def_id(expr.hir_id)?,
2201            typeck.node_args(expr.hir_id),
2202        )),
2203        ExprKind::Call(
2204            Expr {
2205                kind: ExprKind::Path(qpath),
2206                hir_id: path_hir_id,
2207                ..
2208            },
2209            ..,
2210        ) => {
2211            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
2212            // deref to fn pointers, dyn Fn, impl Fn - #8850
2213            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
2214                typeck.qpath_res(qpath, *path_hir_id)
2215            {
2216                Some((id, typeck.node_args(*path_hir_id)))
2217            } else {
2218                None
2219            }
2220        },
2221        _ => None,
2222    }
2223}
2224
2225/// Returns `Option<String>` where String is a textual representation of the type encapsulated in
2226/// the slice iff the given expression is a slice of primitives.
2227///
2228/// (As defined in the `is_recursively_primitive_type` function.) Returns `None` otherwise.
2229pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
2230    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
2231    let expr_kind = expr_type.kind();
2232    let is_primitive = match expr_kind {
2233        rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type),
2234        rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
2235            if let rustc_ty::Slice(element_type) = inner_ty.kind() {
2236                is_recursively_primitive_type(*element_type)
2237            } else {
2238                unreachable!()
2239            }
2240        },
2241        _ => false,
2242    };
2243
2244    if is_primitive {
2245        // if we have wrappers like Array, Slice or Tuple, print these
2246        // and get the type enclosed in the slice ref
2247        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
2248            rustc_ty::Slice(..) => return Some("slice".into()),
2249            rustc_ty::Array(..) => return Some("array".into()),
2250            rustc_ty::Tuple(..) => return Some("tuple".into()),
2251            _ => {
2252                // is_recursively_primitive_type() should have taken care
2253                // of the rest and we can rely on the type that is found
2254                let refs_peeled = expr_type.peel_refs();
2255                return Some(refs_peeled.walk().last().unwrap().to_string());
2256            },
2257        }
2258    }
2259    None
2260}
2261
2262/// Returns a list of groups where elements in each group are equal according to `eq`
2263///
2264/// - Within each group the elements are sorted by the order they appear in `exprs`
2265/// - The groups themselves are sorted by their first element's appearence in `exprs`
2266///
2267/// Given functions `eq` and `hash` such that `eq(a, b) == true`
2268/// implies `hash(a) == hash(b)`
2269pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<Vec<&T>>
2270where
2271    Hash: FnMut(&T) -> u64,
2272    Eq: FnMut(&T, &T) -> bool,
2273{
2274    match exprs {
2275        [a, b] if eq(a, b) => return vec![vec![a, b]],
2276        _ if exprs.len() <= 2 => return vec![],
2277        _ => {},
2278    }
2279
2280    let mut buckets: UnindexMap<u64, Vec<Vec<&T>>> = UnindexMap::default();
2281
2282    for expr in exprs {
2283        match buckets.entry(hash(expr)) {
2284            indexmap::map::Entry::Occupied(mut o) => {
2285                let bucket = o.get_mut();
2286                match bucket.iter_mut().find(|group| eq(expr, group[0])) {
2287                    Some(group) => group.push(expr),
2288                    None => bucket.push(vec![expr]),
2289                }
2290            },
2291            indexmap::map::Entry::Vacant(v) => {
2292                v.insert(vec![vec![expr]]);
2293            },
2294        }
2295    }
2296
2297    buckets
2298        .into_values()
2299        .flatten()
2300        .filter(|group| group.len() > 1)
2301        .collect()
2302}
2303
2304/// Peels off all references on the pattern. Returns the underlying pattern and the number of
2305/// references removed.
2306pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
2307    fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
2308        if let PatKind::Ref(pat, _) = pat.kind {
2309            peel(pat, count + 1)
2310        } else {
2311            (pat, count)
2312        }
2313    }
2314    peel(pat, 0)
2315}
2316
2317/// Peels of expressions while the given closure returns `Some`.
2318pub fn peel_hir_expr_while<'tcx>(
2319    mut expr: &'tcx Expr<'tcx>,
2320    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
2321) -> &'tcx Expr<'tcx> {
2322    while let Some(e) = f(expr) {
2323        expr = e;
2324    }
2325    expr
2326}
2327
2328/// Peels off up to the given number of references on the expression. Returns the underlying
2329/// expression and the number of references removed.
2330pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
2331    let mut remaining = count;
2332    let e = peel_hir_expr_while(expr, |e| match e.kind {
2333        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
2334            remaining -= 1;
2335            Some(e)
2336        },
2337        _ => None,
2338    });
2339    (e, count - remaining)
2340}
2341
2342/// Peels off all unary operators of an expression. Returns the underlying expression and the number
2343/// of operators removed.
2344pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2345    let mut count: usize = 0;
2346    let mut curr_expr = expr;
2347    while let ExprKind::Unary(_, local_expr) = curr_expr.kind {
2348        count = count.wrapping_add(1);
2349        curr_expr = local_expr;
2350    }
2351    (curr_expr, count)
2352}
2353
2354/// Peels off all references on the expression. Returns the underlying expression and the number of
2355/// references removed.
2356pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2357    let mut count = 0;
2358    let e = peel_hir_expr_while(expr, |e| match e.kind {
2359        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
2360            count += 1;
2361            Some(e)
2362        },
2363        _ => None,
2364    });
2365    (e, count)
2366}
2367
2368/// Peels off all references on the type. Returns the underlying type and the number of references
2369/// removed.
2370pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) {
2371    let mut count = 0;
2372    loop {
2373        match &ty.kind {
2374            TyKind::Ref(_, ref_ty) => {
2375                ty = ref_ty.ty;
2376                count += 1;
2377            },
2378            _ => break (ty, count),
2379        }
2380    }
2381}
2382
2383/// Peels off all references on the type. Returns the underlying type and the number of references
2384/// removed.
2385pub fn peel_middle_ty_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
2386    let mut count = 0;
2387    while let rustc_ty::Ref(_, dest_ty, _) = ty.kind() {
2388        ty = *dest_ty;
2389        count += 1;
2390    }
2391    (ty, count)
2392}
2393
2394/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
2395/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
2396pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
2397    loop {
2398        match expr.kind {
2399            ExprKind::AddrOf(_, _, e) => expr = e,
2400            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
2401            _ => break,
2402        }
2403    }
2404    expr
2405}
2406
2407/// Returns a `Vec` of `Expr`s containing `AddrOf` operators (`&`) or deref operators (`*`) of a
2408/// given expression.
2409pub fn get_ref_operators<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Vec<&'hir Expr<'hir>> {
2410    let mut operators = Vec::new();
2411    peel_hir_expr_while(expr, |expr| match expr.kind {
2412        ExprKind::AddrOf(_, _, e) => {
2413            operators.push(expr);
2414            Some(e)
2415        },
2416        ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => {
2417            operators.push(expr);
2418            Some(e)
2419        },
2420        _ => None,
2421    });
2422    operators
2423}
2424
2425pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
2426    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
2427        && let Res::Def(_, def_id) = path.res
2428    {
2429        return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
2430    }
2431    false
2432}
2433
2434static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalModDefId, Vec<Symbol>>>> = OnceLock::new();
2435
2436/// Apply `f()` to the set of test item names.
2437/// The names are sorted using the default `Symbol` ordering.
2438fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&[Symbol]) -> bool) -> bool {
2439    let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
2440    let mut map: MutexGuard<'_, FxHashMap<LocalModDefId, Vec<Symbol>>> = cache.lock().unwrap();
2441    let value = map.entry(module);
2442    match value {
2443        Entry::Occupied(entry) => f(entry.get()),
2444        Entry::Vacant(entry) => {
2445            let mut names = Vec::new();
2446            for id in tcx.hir_module_free_items(module) {
2447                if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
2448                    && let item = tcx.hir_item(id)
2449                    && let ItemKind::Const(ident, _generics, ty, _body) = item.kind
2450                    && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
2451                        // We could also check for the type name `test::TestDescAndFn`
2452                        && let Res::Def(DefKind::Struct, _) = path.res
2453                {
2454                    let has_test_marker = tcx
2455                        .hir_attrs(item.hir_id())
2456                        .iter()
2457                        .any(|a| a.has_name(sym::rustc_test_marker));
2458                    if has_test_marker {
2459                        names.push(ident.name);
2460                    }
2461                }
2462            }
2463            names.sort_unstable();
2464            f(entry.insert(names))
2465        },
2466    }
2467}
2468
2469/// Checks if the function containing the given `HirId` is a `#[test]` function
2470///
2471/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
2472pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
2473    with_test_item_names(tcx, tcx.parent_module(id), |names| {
2474        let node = tcx.hir_node(id);
2475        once((id, node))
2476            .chain(tcx.hir_parent_iter(id))
2477            // Since you can nest functions we need to collect all until we leave
2478            // function scope
2479            .any(|(_id, node)| {
2480                if let Node::Item(item) = node
2481                    && let ItemKind::Fn { ident, .. } = item.kind
2482                {
2483                    // Note that we have sorted the item names in the visitor,
2484                    // so the binary_search gets the same as `contains`, but faster.
2485                    return names.binary_search(&ident.name).is_ok();
2486                }
2487                false
2488            })
2489    })
2490}
2491
2492/// Checks if `fn_def_id` has a `#[test]` attribute applied
2493///
2494/// This only checks directly applied attributes. To see if a node has a parent function marked with
2495/// `#[test]` use [`is_in_test_function`].
2496///
2497/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
2498pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool {
2499    let id = tcx.local_def_id_to_hir_id(fn_def_id);
2500    if let Node::Item(item) = tcx.hir_node(id)
2501        && let ItemKind::Fn { ident, .. } = item.kind
2502    {
2503        with_test_item_names(tcx, tcx.parent_module(id), |names| {
2504            names.binary_search(&ident.name).is_ok()
2505        })
2506    } else {
2507        false
2508    }
2509}
2510
2511/// Checks if `id` has a `#[cfg(test)]` attribute applied
2512///
2513/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
2514/// use [`is_in_cfg_test`]
2515pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
2516    tcx.hir_attrs(id).iter().any(|attr| {
2517        if attr.has_name(sym::cfg_trace)
2518            && let Some(items) = attr.meta_item_list()
2519            && let [item] = &*items
2520            && item.has_name(sym::test)
2521        {
2522            true
2523        } else {
2524            false
2525        }
2526    })
2527}
2528
2529/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
2530pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
2531    tcx.hir_parent_id_iter(id).any(|parent_id| is_cfg_test(tcx, parent_id))
2532}
2533
2534/// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]`
2535pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
2536    is_in_test_function(tcx, hir_id) || is_in_cfg_test(tcx, hir_id)
2537}
2538
2539/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
2540pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
2541    tcx.has_attr(def_id, sym::cfg_trace)
2542        || tcx
2543            .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
2544            .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id))
2545            .any(|attr| attr.has_name(sym::cfg_trace))
2546}
2547
2548/// Walks up the HIR tree from the given expression in an attempt to find where the value is
2549/// consumed.
2550///
2551/// Termination has three conditions:
2552/// - The given function returns `Break`. This function will return the value.
2553/// - The consuming node is found. This function will return `Continue(use_node, child_id)`.
2554/// - No further parent nodes are found. This will trigger a debug assert or return `None`.
2555///
2556/// This allows walking through `if`, `match`, `break`, and block expressions to find where the
2557/// value produced by the expression is consumed.
2558pub fn walk_to_expr_usage<'tcx, T>(
2559    cx: &LateContext<'tcx>,
2560    e: &Expr<'tcx>,
2561    mut f: impl FnMut(HirId, Node<'tcx>, HirId) -> ControlFlow<T>,
2562) -> Option<ControlFlow<T, (Node<'tcx>, HirId)>> {
2563    let mut iter = cx.tcx.hir_parent_iter(e.hir_id);
2564    let mut child_id = e.hir_id;
2565
2566    while let Some((parent_id, parent)) = iter.next() {
2567        if let ControlFlow::Break(x) = f(parent_id, parent, child_id) {
2568            return Some(ControlFlow::Break(x));
2569        }
2570        let parent_expr = match parent {
2571            Node::Expr(e) => e,
2572            Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
2573                child_id = parent_id;
2574                continue;
2575            },
2576            Node::Arm(a) if a.body.hir_id == child_id => {
2577                child_id = parent_id;
2578                continue;
2579            },
2580            _ => return Some(ControlFlow::Continue((parent, child_id))),
2581        };
2582        match parent_expr.kind {
2583            ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
2584            ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
2585                child_id = id;
2586                iter = cx.tcx.hir_parent_iter(id);
2587            },
2588            ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = parent_id,
2589            _ => return Some(ControlFlow::Continue((parent, child_id))),
2590        }
2591    }
2592    debug_assert!(false, "no parent node found for `{child_id:?}`");
2593    None
2594}
2595
2596/// A type definition as it would be viewed from within a function.
2597#[derive(Clone, Copy)]
2598pub enum DefinedTy<'tcx> {
2599    // Used for locals and closures defined within the function.
2600    Hir(&'tcx hir::Ty<'tcx>),
2601    /// Used for function signatures, and constant and static values. The type is
2602    /// in the context of its definition site. We also track the `def_id` of its
2603    /// definition site.
2604    ///
2605    /// WARNING: As the `ty` in in the scope of the definition, not of the function
2606    /// using it, you must be very careful with how you use it. Using it in the wrong
2607    /// scope easily results in ICEs.
2608    Mir {
2609        def_site_def_id: Option<DefId>,
2610        ty: Binder<'tcx, Ty<'tcx>>,
2611    },
2612}
2613
2614/// The context an expressions value is used in.
2615pub struct ExprUseCtxt<'tcx> {
2616    /// The parent node which consumes the value.
2617    pub node: Node<'tcx>,
2618    /// The child id of the node the value came from.
2619    pub child_id: HirId,
2620    /// Any adjustments applied to the type.
2621    pub adjustments: &'tcx [Adjustment<'tcx>],
2622    /// Whether the type must unify with another code path.
2623    pub is_ty_unified: bool,
2624    /// Whether the value will be moved before it's used.
2625    pub moved_before_use: bool,
2626    /// Whether the use site has the same `SyntaxContext` as the value.
2627    pub same_ctxt: bool,
2628}
2629impl<'tcx> ExprUseCtxt<'tcx> {
2630    pub fn use_node(&self, cx: &LateContext<'tcx>) -> ExprUseNode<'tcx> {
2631        match self.node {
2632            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
2633            Node::ExprField(field) => ExprUseNode::Field(field),
2634
2635            Node::Item(&Item {
2636                kind: ItemKind::Static(..) | ItemKind::Const(..),
2637                owner_id,
2638                ..
2639            })
2640            | Node::TraitItem(&TraitItem {
2641                kind: TraitItemKind::Const(..),
2642                owner_id,
2643                ..
2644            })
2645            | Node::ImplItem(&ImplItem {
2646                kind: ImplItemKind::Const(..),
2647                owner_id,
2648                ..
2649            }) => ExprUseNode::ConstStatic(owner_id),
2650
2651            Node::Item(&Item {
2652                kind: ItemKind::Fn { .. },
2653                owner_id,
2654                ..
2655            })
2656            | Node::TraitItem(&TraitItem {
2657                kind: TraitItemKind::Fn(..),
2658                owner_id,
2659                ..
2660            })
2661            | Node::ImplItem(&ImplItem {
2662                kind: ImplItemKind::Fn(..),
2663                owner_id,
2664                ..
2665            }) => ExprUseNode::Return(owner_id),
2666
2667            Node::Expr(use_expr) => match use_expr.kind {
2668                ExprKind::Ret(_) => ExprUseNode::Return(OwnerId {
2669                    def_id: cx.tcx.hir_body_owner_def_id(cx.enclosing_body.unwrap()),
2670                }),
2671
2672                ExprKind::Closure(closure) => ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
2673                ExprKind::Call(func, args) => match args.iter().position(|arg| arg.hir_id == self.child_id) {
2674                    Some(i) => ExprUseNode::FnArg(func, i),
2675                    None => ExprUseNode::Callee,
2676                },
2677                ExprKind::MethodCall(name, _, args, _) => ExprUseNode::MethodArg(
2678                    use_expr.hir_id,
2679                    name.args,
2680                    args.iter()
2681                        .position(|arg| arg.hir_id == self.child_id)
2682                        .map_or(0, |i| i + 1),
2683                ),
2684                ExprKind::Field(_, name) => ExprUseNode::FieldAccess(name),
2685                ExprKind::AddrOf(kind, mutbl, _) => ExprUseNode::AddrOf(kind, mutbl),
2686                _ => ExprUseNode::Other,
2687            },
2688            _ => ExprUseNode::Other,
2689        }
2690    }
2691}
2692
2693/// The node which consumes a value.
2694pub enum ExprUseNode<'tcx> {
2695    /// Assignment to, or initializer for, a local
2696    LetStmt(&'tcx LetStmt<'tcx>),
2697    /// Initializer for a const or static item.
2698    ConstStatic(OwnerId),
2699    /// Implicit or explicit return from a function.
2700    Return(OwnerId),
2701    /// Initialization of a struct field.
2702    Field(&'tcx ExprField<'tcx>),
2703    /// An argument to a function.
2704    FnArg(&'tcx Expr<'tcx>, usize),
2705    /// An argument to a method.
2706    MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
2707    /// The callee of a function call.
2708    Callee,
2709    /// Access of a field.
2710    FieldAccess(Ident),
2711    /// Borrow expression.
2712    AddrOf(ast::BorrowKind, Mutability),
2713    Other,
2714}
2715impl<'tcx> ExprUseNode<'tcx> {
2716    /// Checks if the value is returned from the function.
2717    pub fn is_return(&self) -> bool {
2718        matches!(self, Self::Return(_))
2719    }
2720
2721    /// Checks if the value is used as a method call receiver.
2722    pub fn is_recv(&self) -> bool {
2723        matches!(self, Self::MethodArg(_, _, 0))
2724    }
2725
2726    /// Gets the needed type as it's defined without any type inference.
2727    pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
2728        match *self {
2729            Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
2730            Self::ConstStatic(id) => Some(DefinedTy::Mir {
2731                def_site_def_id: Some(id.def_id.to_def_id()),
2732                ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()),
2733            }),
2734            Self::Return(id) => {
2735                if let Node::Expr(Expr {
2736                    kind: ExprKind::Closure(c),
2737                    ..
2738                }) = cx.tcx.hir_node_by_def_id(id.def_id)
2739                {
2740                    match c.fn_decl.output {
2741                        FnRetTy::DefaultReturn(_) => None,
2742                        FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
2743                    }
2744                } else {
2745                    let ty = cx.tcx.fn_sig(id).instantiate_identity().output();
2746                    Some(DefinedTy::Mir {
2747                        def_site_def_id: Some(id.def_id.to_def_id()),
2748                        ty,
2749                    })
2750                }
2751            },
2752            Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
2753                Some(Expr {
2754                    hir_id,
2755                    kind: ExprKind::Struct(path, ..),
2756                    ..
2757                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
2758                    .and_then(|(adt, variant)| {
2759                        variant
2760                            .fields
2761                            .iter()
2762                            .find(|f| f.name == field.ident.name)
2763                            .map(|f| (adt, f))
2764                    })
2765                    .map(|(adt, field_def)| DefinedTy::Mir {
2766                        def_site_def_id: Some(adt.did()),
2767                        ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()),
2768                    }),
2769                _ => None,
2770            },
2771            Self::FnArg(callee, i) => {
2772                let sig = expr_sig(cx, callee)?;
2773                let (hir_ty, ty) = sig.input_with_hir(i)?;
2774                Some(match hir_ty {
2775                    Some(hir_ty) => DefinedTy::Hir(hir_ty),
2776                    None => DefinedTy::Mir {
2777                        def_site_def_id: sig.predicates_id(),
2778                        ty,
2779                    },
2780                })
2781            },
2782            Self::MethodArg(id, _, i) => {
2783                let id = cx.typeck_results().type_dependent_def_id(id)?;
2784                let sig = cx.tcx.fn_sig(id).skip_binder();
2785                Some(DefinedTy::Mir {
2786                    def_site_def_id: Some(id),
2787                    ty: sig.input(i),
2788                })
2789            },
2790            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None,
2791        }
2792    }
2793}
2794
2795/// Gets the context an expression's value is used in.
2796pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtxt<'tcx> {
2797    let mut adjustments = [].as_slice();
2798    let mut is_ty_unified = false;
2799    let mut moved_before_use = false;
2800    let mut same_ctxt = true;
2801    let ctxt = e.span.ctxt();
2802    let node = walk_to_expr_usage(cx, e, &mut |parent_id, parent, child_id| -> ControlFlow<!> {
2803        if adjustments.is_empty()
2804            && let Node::Expr(e) = cx.tcx.hir_node(child_id)
2805        {
2806            adjustments = cx.typeck_results().expr_adjustments(e);
2807        }
2808        same_ctxt &= cx.tcx.hir_span(parent_id).ctxt() == ctxt;
2809        if let Node::Expr(e) = parent {
2810            match e.kind {
2811                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
2812                    is_ty_unified = true;
2813                    moved_before_use = true;
2814                },
2815                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
2816                    is_ty_unified = true;
2817                    moved_before_use = true;
2818                },
2819                ExprKind::Block(..) => moved_before_use = true,
2820                _ => {},
2821            }
2822        }
2823        ControlFlow::Continue(())
2824    });
2825    match node {
2826        Some(ControlFlow::Continue((node, child_id))) => ExprUseCtxt {
2827            node,
2828            child_id,
2829            adjustments,
2830            is_ty_unified,
2831            moved_before_use,
2832            same_ctxt,
2833        },
2834        #[allow(unreachable_patterns)]
2835        Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
2836        None => ExprUseCtxt {
2837            node: Node::Crate(cx.tcx.hir_root_module()),
2838            child_id: HirId::INVALID,
2839            adjustments: &[],
2840            is_ty_unified: true,
2841            moved_before_use: true,
2842            same_ctxt: false,
2843        },
2844    }
2845}
2846
2847/// Tokenizes the input while keeping the text associated with each token.
2848pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, InnerSpan)> {
2849    let mut pos = 0;
2850    tokenize(s, FrontmatterAllowed::No).map(move |t| {
2851        let end = pos + t.len;
2852        let range = pos as usize..end as usize;
2853        let inner = InnerSpan::new(range.start, range.end);
2854        pos = end;
2855        (t.kind, s.get(range).unwrap_or_default(), inner)
2856    })
2857}
2858
2859/// Checks whether a given span has any comment token
2860/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
2861pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
2862    let Ok(snippet) = sm.span_to_snippet(span) else {
2863        return false;
2864    };
2865    return tokenize(&snippet, FrontmatterAllowed::No).any(|token| {
2866        matches!(
2867            token.kind,
2868            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
2869        )
2870    });
2871}
2872
2873/// Checks whether a given span has any significant token. A significant token is a non-whitespace
2874/// token, including comments unless `skip_comments` is set.
2875/// This is useful to determine if there are any actual code tokens in the span that are omitted in
2876/// the late pass, such as platform-specific code.
2877pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
2878    matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
2879        match token {
2880            TokenKind::Whitespace => false,
2881            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
2882            _ => true,
2883        }
2884    ))
2885}
2886/// Returns all the comments a given span contains
2887///
2888/// Comments are returned wrapped with their relevant delimiters
2889pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
2890    span_extract_comments(sm, span).join("\n")
2891}
2892
2893/// Returns all the comments a given span contains.
2894///
2895/// Comments are returned wrapped with their relevant delimiters.
2896pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec<String> {
2897    let snippet = sm.span_to_snippet(span).unwrap_or_default();
2898    tokenize_with_text(&snippet)
2899        .filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
2900        .map(|(_, s, _)| s.to_string())
2901        .collect::<Vec<_>>()
2902}
2903
2904pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
2905    sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
2906}
2907
2908/// Returns whether the given let pattern and else body can be turned into the `?` operator
2909///
2910/// For this example:
2911/// ```ignore
2912/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None };
2913/// ```
2914/// We get as parameters:
2915/// ```ignore
2916/// pat: Some(a)
2917/// else_body: return None
2918/// ```
2919///
2920/// And for this example:
2921/// ```ignore
2922/// let Some(FooBar { a, b }) = ex else { return None };
2923/// ```
2924/// We get as parameters:
2925/// ```ignore
2926/// pat: Some(FooBar { a, b })
2927/// else_body: return None
2928/// ```
2929///
2930/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
2931/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not.
2932pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
2933    cx: &LateContext<'_>,
2934    pat: &'a Pat<'hir>,
2935    else_body: &Expr<'_>,
2936) -> Option<&'a Pat<'hir>> {
2937    if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind
2938        && is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome)
2939        && !is_refutable(cx, inner_pat)
2940        && let else_body = peel_blocks(else_body)
2941        && let ExprKind::Ret(Some(ret_val)) = else_body.kind
2942        && let ExprKind::Path(ret_path) = ret_val.kind
2943        && is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
2944    {
2945        Some(inner_pat)
2946    } else {
2947        None
2948    }
2949}
2950
2951macro_rules! op_utils {
2952    ($($name:ident $assign:ident)*) => {
2953        /// Binary operation traits like `LangItem::Add`
2954        pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
2955
2956        /// Operator-Assign traits like `LangItem::AddAssign`
2957        pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
2958
2959        /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
2960        pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
2961            match kind {
2962                $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
2963                _ => None,
2964            }
2965        }
2966    };
2967}
2968
2969op_utils! {
2970    Add    AddAssign
2971    Sub    SubAssign
2972    Mul    MulAssign
2973    Div    DivAssign
2974    Rem    RemAssign
2975    BitXor BitXorAssign
2976    BitAnd BitAndAssign
2977    BitOr  BitOrAssign
2978    Shl    ShlAssign
2979    Shr    ShrAssign
2980}
2981
2982/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
2983/// that is not locally used.
2984pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool {
2985    match *pat {
2986        PatKind::Wild => true,
2987        PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => {
2988            !visitors::is_local_used(cx, body, id)
2989        },
2990        _ => false,
2991    }
2992}
2993
2994#[derive(Clone, Copy)]
2995pub enum RequiresSemi {
2996    Yes,
2997    No,
2998}
2999impl RequiresSemi {
3000    pub fn requires_semi(self) -> bool {
3001        matches!(self, Self::Yes)
3002    }
3003}
3004
3005/// Check if the expression return `!`, a type coerced from `!`, or could return `!` if the final
3006/// expression were turned into a statement.
3007#[expect(clippy::too_many_lines)]
3008pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<RequiresSemi> {
3009    struct BreakTarget {
3010        id: HirId,
3011        unused: bool,
3012    }
3013
3014    struct V<'cx, 'tcx> {
3015        cx: &'cx LateContext<'tcx>,
3016        break_targets: Vec<BreakTarget>,
3017        break_targets_for_result_ty: u32,
3018        in_final_expr: bool,
3019        requires_semi: bool,
3020        is_never: bool,
3021    }
3022
3023    impl V<'_, '_> {
3024        fn push_break_target(&mut self, id: HirId) {
3025            self.break_targets.push(BreakTarget { id, unused: true });
3026            self.break_targets_for_result_ty += u32::from(self.in_final_expr);
3027        }
3028    }
3029
3030    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
3031        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
3032            // Note: Part of the complexity here comes from the fact that
3033            // coercions are applied to the innermost expression.
3034            // e.g. In `let x: u32 = { break () };` the never-to-any coercion
3035            // is applied to the break expression. This means we can't just
3036            // check the block's type as it will be `u32` despite the fact
3037            // that the block always diverges.
3038
3039            // The rest of the complexity comes from checking blocks which
3040            // syntactically return a value, but will always diverge before
3041            // reaching that point.
3042            // e.g. In `let x = { foo(panic!()) };` the block's type will be the
3043            // return type of `foo` even though it will never actually run. This
3044            // can be trivially fixed by adding a semicolon after the call, but
3045            // we must first detect that a semicolon is needed to make that
3046            // suggestion.
3047
3048            if self.is_never && self.break_targets.is_empty() {
3049                if self.in_final_expr && !self.requires_semi {
3050                    // This expression won't ever run, but we still need to check
3051                    // if it can affect the type of the final expression.
3052                    match e.kind {
3053                        ExprKind::DropTemps(e) => self.visit_expr(e),
3054                        ExprKind::If(_, then, Some(else_)) => {
3055                            self.visit_expr(then);
3056                            self.visit_expr(else_);
3057                        },
3058                        ExprKind::Match(_, arms, _) => {
3059                            for arm in arms {
3060                                self.visit_expr(arm.body);
3061                            }
3062                        },
3063                        ExprKind::Loop(b, ..) => {
3064                            self.push_break_target(e.hir_id);
3065                            self.in_final_expr = false;
3066                            self.visit_block(b);
3067                            self.break_targets.pop();
3068                        },
3069                        ExprKind::Block(b, _) => {
3070                            if b.targeted_by_break {
3071                                self.push_break_target(b.hir_id);
3072                                self.visit_block(b);
3073                                self.break_targets.pop();
3074                            } else {
3075                                self.visit_block(b);
3076                            }
3077                        },
3078                        _ => {
3079                            self.requires_semi = !self.cx.typeck_results().expr_ty(e).is_never();
3080                        },
3081                    }
3082                }
3083                return;
3084            }
3085            match e.kind {
3086                ExprKind::DropTemps(e) => self.visit_expr(e),
3087                ExprKind::Ret(None) | ExprKind::Continue(_) => self.is_never = true,
3088                ExprKind::Ret(Some(e)) | ExprKind::Become(e) => {
3089                    self.in_final_expr = false;
3090                    self.visit_expr(e);
3091                    self.is_never = true;
3092                },
3093                ExprKind::Break(dest, e) => {
3094                    if let Some(e) = e {
3095                        self.in_final_expr = false;
3096                        self.visit_expr(e);
3097                    }
3098                    if let Ok(id) = dest.target_id
3099                        && let Some((i, target)) = self
3100                            .break_targets
3101                            .iter_mut()
3102                            .enumerate()
3103                            .find(|(_, target)| target.id == id)
3104                    {
3105                        target.unused &= self.is_never;
3106                        if i < self.break_targets_for_result_ty as usize {
3107                            self.requires_semi = true;
3108                        }
3109                    }
3110                    self.is_never = true;
3111                },
3112                ExprKind::If(cond, then, else_) => {
3113                    let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3114                    self.visit_expr(cond);
3115                    self.in_final_expr = in_final_expr;
3116
3117                    if self.is_never {
3118                        self.visit_expr(then);
3119                        if let Some(else_) = else_ {
3120                            self.visit_expr(else_);
3121                        }
3122                    } else {
3123                        self.visit_expr(then);
3124                        let is_never = mem::replace(&mut self.is_never, false);
3125                        if let Some(else_) = else_ {
3126                            self.visit_expr(else_);
3127                            self.is_never &= is_never;
3128                        }
3129                    }
3130                },
3131                ExprKind::Match(scrutinee, arms, _) => {
3132                    let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3133                    self.visit_expr(scrutinee);
3134                    self.in_final_expr = in_final_expr;
3135
3136                    if self.is_never {
3137                        for arm in arms {
3138                            self.visit_arm(arm);
3139                        }
3140                    } else {
3141                        let mut is_never = true;
3142                        for arm in arms {
3143                            self.is_never = false;
3144                            if let Some(guard) = arm.guard {
3145                                let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3146                                self.visit_expr(guard);
3147                                self.in_final_expr = in_final_expr;
3148                                // The compiler doesn't consider diverging guards as causing the arm to diverge.
3149                                self.is_never = false;
3150                            }
3151                            self.visit_expr(arm.body);
3152                            is_never &= self.is_never;
3153                        }
3154                        self.is_never = is_never;
3155                    }
3156                },
3157                ExprKind::Loop(b, _, _, _) => {
3158                    self.push_break_target(e.hir_id);
3159                    self.in_final_expr = false;
3160                    self.visit_block(b);
3161                    self.is_never = self.break_targets.pop().unwrap().unused;
3162                },
3163                ExprKind::Block(b, _) => {
3164                    if b.targeted_by_break {
3165                        self.push_break_target(b.hir_id);
3166                        self.visit_block(b);
3167                        self.is_never &= self.break_targets.pop().unwrap().unused;
3168                    } else {
3169                        self.visit_block(b);
3170                    }
3171                },
3172                _ => {
3173                    self.in_final_expr = false;
3174                    walk_expr(self, e);
3175                    self.is_never |= self.cx.typeck_results().expr_ty(e).is_never();
3176                },
3177            }
3178        }
3179
3180        fn visit_block(&mut self, b: &'tcx Block<'_>) {
3181            let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3182            for s in b.stmts {
3183                self.visit_stmt(s);
3184            }
3185            self.in_final_expr = in_final_expr;
3186            if let Some(e) = b.expr {
3187                self.visit_expr(e);
3188            }
3189        }
3190
3191        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
3192            if let Some(e) = l.init {
3193                self.visit_expr(e);
3194            }
3195            if let Some(else_) = l.els {
3196                let is_never = self.is_never;
3197                self.visit_block(else_);
3198                self.is_never = is_never;
3199            }
3200        }
3201
3202        fn visit_arm(&mut self, arm: &Arm<'tcx>) {
3203            if let Some(guard) = arm.guard {
3204                let in_final_expr = mem::replace(&mut self.in_final_expr, false);
3205                self.visit_expr(guard);
3206                self.in_final_expr = in_final_expr;
3207            }
3208            self.visit_expr(arm.body);
3209        }
3210    }
3211
3212    if cx.typeck_results().expr_ty(e).is_never() {
3213        Some(RequiresSemi::No)
3214    } else if let ExprKind::Block(b, _) = e.kind
3215        && !b.targeted_by_break
3216        && b.expr.is_none()
3217    {
3218        // If a block diverges without a final expression then it's type is `!`.
3219        None
3220    } else {
3221        let mut v = V {
3222            cx,
3223            break_targets: Vec::new(),
3224            break_targets_for_result_ty: 0,
3225            in_final_expr: true,
3226            requires_semi: false,
3227            is_never: false,
3228        };
3229        v.visit_expr(e);
3230        v.is_never
3231            .then_some(if v.requires_semi && matches!(e.kind, ExprKind::Block(..)) {
3232                RequiresSemi::Yes
3233            } else {
3234                RequiresSemi::No
3235            })
3236    }
3237}
3238
3239/// Produces a path from a local caller to the type of the called method. Suitable for user
3240/// output/suggestions.
3241///
3242/// Returned path can be either absolute (for methods defined non-locally), or relative (for local
3243/// methods).
3244pub fn get_path_from_caller_to_method_type<'tcx>(
3245    tcx: TyCtxt<'tcx>,
3246    from: LocalDefId,
3247    method: DefId,
3248    args: GenericArgsRef<'tcx>,
3249) -> String {
3250    let assoc_item = tcx.associated_item(method);
3251    let def_id = assoc_item.container_id(tcx);
3252    match assoc_item.container {
3253        rustc_ty::AssocItemContainer::Trait => get_path_to_callee(tcx, from, def_id),
3254        rustc_ty::AssocItemContainer::Impl => {
3255            let ty = tcx.type_of(def_id).instantiate_identity();
3256            get_path_to_ty(tcx, from, ty, args)
3257        },
3258    }
3259}
3260
3261fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args: GenericArgsRef<'tcx>) -> String {
3262    match ty.kind() {
3263        rustc_ty::Adt(adt, _) => get_path_to_callee(tcx, from, adt.did()),
3264        // TODO these types need to be recursively resolved as well
3265        rustc_ty::Array(..)
3266        | rustc_ty::Dynamic(..)
3267        | rustc_ty::Never
3268        | rustc_ty::RawPtr(_, _)
3269        | rustc_ty::Ref(..)
3270        | rustc_ty::Slice(_)
3271        | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)),
3272        _ => ty.to_string(),
3273    }
3274}
3275
3276/// Produce a path from some local caller to the callee. Suitable for user output/suggestions.
3277fn get_path_to_callee(tcx: TyCtxt<'_>, from: LocalDefId, callee: DefId) -> String {
3278    // only search for a relative path if the call is fully local
3279    if callee.is_local() {
3280        let callee_path = tcx.def_path(callee);
3281        let caller_path = tcx.def_path(from.to_def_id());
3282        maybe_get_relative_path(&caller_path, &callee_path, 2)
3283    } else {
3284        tcx.def_path_str(callee)
3285    }
3286}
3287
3288/// Tries to produce a relative path from `from` to `to`; if such a path would contain more than
3289/// `max_super` `super` items, produces an absolute path instead. Both `from` and `to` should be in
3290/// the local crate.
3291///
3292/// Suitable for user output/suggestions.
3293///
3294/// This ignores use items, and assumes that the target path is visible from the source
3295/// path (which _should_ be a reasonable assumption since we in order to be able to use an object of
3296/// certain type T, T is required to be visible).
3297///
3298/// TODO make use of `use` items. Maybe we should have something more sophisticated like
3299/// rust-analyzer does? <https://docs.rs/ra_ap_hir_def/0.0.169/src/ra_ap_hir_def/find_path.rs.html#19-27>
3300fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> String {
3301    use itertools::EitherOrBoth::{Both, Left, Right};
3302
3303    // 1. skip the segments common for both paths (regardless of their type)
3304    let unique_parts = to
3305        .data
3306        .iter()
3307        .zip_longest(from.data.iter())
3308        .skip_while(|el| matches!(el, Both(l, r) if l == r))
3309        .map(|el| match el {
3310            Both(l, r) => Both(l.data, r.data),
3311            Left(l) => Left(l.data),
3312            Right(r) => Right(r.data),
3313        });
3314
3315    // 2. for the remaining segments, construct relative path using only mod names and `super`
3316    let mut go_up_by = 0;
3317    let mut path = Vec::new();
3318    for el in unique_parts {
3319        match el {
3320            Both(l, r) => {
3321                // consider:
3322                // a::b::sym:: ::    refers to
3323                // c::d::e  ::f::sym
3324                // result should be super::super::c::d::e::f
3325                //
3326                // alternatively:
3327                // a::b::c  ::d::sym refers to
3328                // e::f::sym:: ::
3329                // result should be super::super::super::super::e::f
3330                if let DefPathData::TypeNs(sym) = l {
3331                    path.push(sym);
3332                }
3333                if let DefPathData::TypeNs(_) = r {
3334                    go_up_by += 1;
3335                }
3336            },
3337            // consider:
3338            // a::b::sym:: ::    refers to
3339            // c::d::e  ::f::sym
3340            // when looking at `f`
3341            Left(DefPathData::TypeNs(sym)) => path.push(sym),
3342            // consider:
3343            // a::b::c  ::d::sym refers to
3344            // e::f::sym:: ::
3345            // when looking at `d`
3346            Right(DefPathData::TypeNs(_)) => go_up_by += 1,
3347            _ => {},
3348        }
3349    }
3350
3351    if go_up_by > max_super {
3352        // `super` chain would be too long, just use the absolute path instead
3353        join_path_syms(once(kw::Crate).chain(to.data.iter().filter_map(|el| {
3354            if let DefPathData::TypeNs(sym) = el.data {
3355                Some(sym)
3356            } else {
3357                None
3358            }
3359        })))
3360    } else {
3361        join_path_syms(repeat_n(kw::Super, go_up_by).chain(path))
3362    }
3363}
3364
3365/// Returns true if the specified `HirId` is the top-level expression of a statement or the only
3366/// expression in a block.
3367pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
3368    matches!(
3369        cx.tcx.parent_hir_node(id),
3370        Node::Stmt(..) | Node::Block(Block { stmts: [], .. })
3371    )
3372}
3373
3374/// Returns true if the given `expr` is a block or resembled as a block,
3375/// such as `if`, `loop`, `match` expressions etc.
3376pub fn is_block_like(expr: &Expr<'_>) -> bool {
3377    matches!(
3378        expr.kind,
3379        ExprKind::Block(..) | ExprKind::ConstBlock(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..)
3380    )
3381}
3382
3383/// Returns true if the given `expr` is binary expression that needs to be wrapped in parentheses.
3384pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool {
3385    fn contains_block(expr: &Expr<'_>, is_operand: bool) -> bool {
3386        match expr.kind {
3387            ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => contains_block(lhs, true),
3388            _ if is_block_like(expr) => is_operand,
3389            _ => false,
3390        }
3391    }
3392
3393    contains_block(expr, false)
3394}
3395
3396/// Returns true if the specified expression is in a receiver position.
3397pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3398    if let Some(parent_expr) = get_parent_expr(cx, expr)
3399        && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind
3400        && receiver.hir_id == expr.hir_id
3401    {
3402        return true;
3403    }
3404    false
3405}
3406
3407/// Returns true if `expr` creates any temporary whose type references a non-static lifetime and has
3408/// a significant drop and does not consume it.
3409pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
3410    for_each_unconsumed_temporary(cx, expr, |temporary_ty| {
3411        if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env())
3412            && temporary_ty
3413                .walk()
3414                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
3415        {
3416            ControlFlow::Break(())
3417        } else {
3418            ControlFlow::Continue(())
3419        }
3420    })
3421    .is_break()
3422}
3423
3424/// Returns true if the specified `expr` requires coercion,
3425/// meaning that it either has a coercion or propagates a coercion from one of its sub expressions.
3426///
3427/// Similar to [`is_adjusted`], this not only checks if an expression's type was adjusted,
3428/// but also going through extra steps to see if it fits the description of [coercion sites].
3429///
3430/// You should used this when you want to avoid suggesting replacing an expression that is currently
3431/// a coercion site or coercion propagating expression with one that is not.
3432///
3433/// [coercion sites]: https://doc.rust-lang.org/stable/reference/type-coercions.html#coercion-sites
3434pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
3435    let expr_ty_is_adjusted = cx
3436        .typeck_results()
3437        .expr_adjustments(expr)
3438        .iter()
3439        // ignore `NeverToAny` adjustments, such as `panic!` call.
3440        .any(|adj| !matches!(adj.kind, Adjust::NeverToAny));
3441    if expr_ty_is_adjusted {
3442        return true;
3443    }
3444
3445    // Identify coercion sites and recursively check if those sites
3446    // actually have type adjustments.
3447    match expr.kind {
3448        ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => {
3449            let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
3450
3451            if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) {
3452                return false;
3453            }
3454
3455            let self_arg_count = usize::from(matches!(expr.kind, ExprKind::MethodCall(..)));
3456            let mut args_with_ty_param = {
3457                fn_sig
3458                    .inputs()
3459                    .skip_binder()
3460                    .iter()
3461                    .skip(self_arg_count)
3462                    .zip(args)
3463                    .filter_map(|(arg_ty, arg)| {
3464                        if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) {
3465                            Some(arg)
3466                        } else {
3467                            None
3468                        }
3469                    })
3470            };
3471            args_with_ty_param.any(|arg| expr_requires_coercion(cx, arg))
3472        },
3473        // Struct/union initialization.
3474        ExprKind::Struct(qpath, _, _) => {
3475            let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
3476            if let Some((_, v_def)) = adt_and_variant_of_res(cx, res) {
3477                let rustc_ty::Adt(_, generic_args) = cx.typeck_results().expr_ty_adjusted(expr).kind() else {
3478                    // This should never happen, but when it does, not linting is the better option.
3479                    return true;
3480                };
3481                v_def
3482                    .fields
3483                    .iter()
3484                    .any(|field| field.ty(cx.tcx, generic_args).has_type_flags(TypeFlags::HAS_TY_PARAM))
3485            } else {
3486                false
3487            }
3488        },
3489        // Function results, including the final line of a block or a `return` expression.
3490        ExprKind::Block(
3491            &Block {
3492                expr: Some(ret_expr), ..
3493            },
3494            _,
3495        )
3496        | ExprKind::Ret(Some(ret_expr)) => expr_requires_coercion(cx, ret_expr),
3497
3498        // ===== Coercion-propagation expressions =====
3499        ExprKind::Array(elems) | ExprKind::Tup(elems) => elems.iter().any(|elem| expr_requires_coercion(cx, elem)),
3500        // Array but with repeating syntax.
3501        ExprKind::Repeat(rep_elem, _) => expr_requires_coercion(cx, rep_elem),
3502        // Others that may contain coercion sites.
3503        ExprKind::If(_, then, maybe_else) => {
3504            expr_requires_coercion(cx, then) || maybe_else.is_some_and(|e| expr_requires_coercion(cx, e))
3505        },
3506        ExprKind::Match(_, arms, _) => arms
3507            .iter()
3508            .map(|arm| arm.body)
3509            .any(|body| expr_requires_coercion(cx, body)),
3510        _ => false,
3511    }
3512}
3513
3514/// Returns `true` if `expr` designates a mutable static, a mutable local binding, or an expression
3515/// that can be owned.
3516pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3517    if let Some(hir_id) = path_to_local(expr)
3518        && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
3519    {
3520        matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
3521    } else if let ExprKind::Path(p) = &expr.kind
3522        && let Some(mutability) = cx
3523            .qpath_res(p, expr.hir_id)
3524            .opt_def_id()
3525            .and_then(|id| cx.tcx.static_mutability(id))
3526    {
3527        mutability == Mutability::Mut
3528    } else if let ExprKind::Field(parent, _) = expr.kind {
3529        is_mutable(cx, parent)
3530    } else {
3531        true
3532    }
3533}
3534
3535/// Peel `Option<…>` from `hir_ty` as long as the HIR name is `Option` and it corresponds to the
3536/// `core::Option<_>` type.
3537pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
3538    let Some(option_def_id) = cx.tcx.get_diagnostic_item(sym::Option) else {
3539        return hir_ty;
3540    };
3541    while let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind
3542        && let Some(segment) = path.segments.last()
3543        && segment.ident.name == sym::Option
3544        && let Res::Def(DefKind::Enum, def_id) = segment.res
3545        && def_id == option_def_id
3546        && let [GenericArg::Type(arg_ty)] = segment.args().args
3547    {
3548        hir_ty = arg_ty.as_unambig_ty();
3549    }
3550    hir_ty
3551}
3552
3553/// If `expr` is a desugared `.await`, return the original expression if it does not come from a
3554/// macro expansion.
3555pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
3556    if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind
3557        && let ExprKind::Call(_, [into_future_arg]) = match_value.kind
3558        && let ctxt = expr.span.ctxt()
3559        && for_each_expr_without_closures(into_future_arg, |e| {
3560            walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))
3561        })
3562        .is_none()
3563    {
3564        Some(into_future_arg)
3565    } else {
3566        None
3567    }
3568}
3569
3570/// Checks if the given expression is a call to `Default::default()`.
3571pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
3572    if let ExprKind::Call(fn_expr, []) = &expr.kind
3573        && let ExprKind::Path(qpath) = &fn_expr.kind
3574        && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
3575    {
3576        cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
3577    } else {
3578        false
3579    }
3580}
3581
3582/// Checks if `expr` may be directly used as the return value of its enclosing body.
3583/// The following cases are covered:
3584/// - `expr` as the last expression of the body, or of a block that can be used as the return value
3585/// - `return expr`
3586/// - then or else part of a `if` in return position
3587/// - arm body of a `match` in a return position
3588/// - `break expr` or `break 'label expr` if the loop or block being exited is used as a return
3589///   value
3590///
3591/// Contrary to [`TyCtxt::hir_get_fn_id_for_return_block()`], if `expr` is part of a
3592/// larger expression, for example a field expression of a `struct`, it will not be
3593/// considered as matching the condition and will return `false`.
3594///
3595/// Also, even if `expr` is assigned to a variable which is later returned, this function
3596/// will still return `false` because `expr` is not used *directly* as the return value
3597/// as it goes through the intermediate variable.
3598pub fn potential_return_of_enclosing_body(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3599    let enclosing_body_owner = cx
3600        .tcx
3601        .local_def_id_to_hir_id(cx.tcx.hir_enclosing_body_owner(expr.hir_id));
3602    let mut prev_id = expr.hir_id;
3603    let mut skip_until_id = None;
3604    for (hir_id, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
3605        if hir_id == enclosing_body_owner {
3606            return true;
3607        }
3608        if let Some(id) = skip_until_id {
3609            prev_id = hir_id;
3610            if id == hir_id {
3611                skip_until_id = None;
3612            }
3613            continue;
3614        }
3615        match node {
3616            Node::Block(Block { expr, .. }) if expr.is_some_and(|expr| expr.hir_id == prev_id) => {},
3617            Node::Arm(arm) if arm.body.hir_id == prev_id => {},
3618            Node::Expr(expr) => match expr.kind {
3619                ExprKind::Ret(_) => return true,
3620                ExprKind::If(_, then, opt_else)
3621                    if then.hir_id == prev_id || opt_else.is_some_and(|els| els.hir_id == prev_id) => {},
3622                ExprKind::Match(_, arms, _) if arms.iter().any(|arm| arm.hir_id == prev_id) => {},
3623                ExprKind::Block(block, _) if block.hir_id == prev_id => {},
3624                ExprKind::Break(
3625                    Destination {
3626                        target_id: Ok(target_id),
3627                        ..
3628                    },
3629                    _,
3630                ) => skip_until_id = Some(target_id),
3631                _ => break,
3632            },
3633            _ => break,
3634        }
3635        prev_id = hir_id;
3636    }
3637
3638    // `expr` is used as part of "something" and is not returned directly from its
3639    // enclosing body.
3640    false
3641}
3642
3643/// Checks if the expression has adjustments that require coercion, for example: dereferencing with
3644/// overloaded deref, coercing pointers and `dyn` objects.
3645pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
3646    cx.typeck_results().expr_adjustments(expr).iter().any(|adj| {
3647        matches!(
3648            adj.kind,
3649            Adjust::Deref(Some(_)) | Adjust::Pointer(PointerCoercion::Unsize) | Adjust::NeverToAny
3650        )
3651    })
3652}
3653
3654/// Checks if the expression is an async block (i.e., `async { ... }`).
3655pub fn is_expr_async_block(expr: &Expr<'_>) -> bool {
3656    matches!(
3657        expr.kind,
3658        ExprKind::Closure(Closure {
3659            kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(
3660                CoroutineDesugaring::Async,
3661                CoroutineSource::Block
3662            )),
3663            ..
3664        })
3665    )
3666}