clippy_utils/
lib.rs

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