clippy_utils/
lib.rs

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