clippy_utils/
lib.rs

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