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