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