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