clippy_utils/
lib.rs

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