clippy_utils/
lib.rs

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