• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![feature(array_chunks)]
2 #![feature(box_patterns)]
3 #![feature(if_let_guard)]
4 #![feature(let_chains)]
5 #![feature(lint_reasons)]
6 #![feature(never_type)]
7 #![feature(rustc_private)]
8 #![recursion_limit = "512"]
9 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
10 #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
11 // warn on the same lints as `clippy_lints`
12 #![warn(trivial_casts, trivial_numeric_casts)]
13 // warn on lints, that are included in `rust-lang/rust`s bootstrap
14 #![warn(rust_2018_idioms, unused_lifetimes)]
15 // warn on rustc internal lints
16 #![warn(rustc::internal)]
17 
18 // FIXME: switch to something more ergonomic here, once available.
19 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
20 extern crate rustc_ast;
21 extern crate rustc_ast_pretty;
22 extern crate rustc_attr;
23 extern crate rustc_const_eval;
24 extern crate rustc_data_structures;
25 // The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate.
26 #[allow(unused_extern_crates)]
27 extern crate rustc_driver;
28 extern crate rustc_errors;
29 extern crate rustc_hir;
30 extern crate rustc_hir_typeck;
31 extern crate rustc_index;
32 extern crate rustc_infer;
33 extern crate rustc_lexer;
34 extern crate rustc_lint;
35 extern crate rustc_middle;
36 extern crate rustc_mir_dataflow;
37 extern crate rustc_session;
38 extern crate rustc_span;
39 extern crate rustc_target;
40 extern crate rustc_trait_selection;
41 
42 #[macro_use]
43 pub mod sym_helper;
44 
45 pub mod ast_utils;
46 pub mod attrs;
47 mod check_proc_macro;
48 pub mod comparisons;
49 pub mod consts;
50 pub mod diagnostics;
51 pub mod eager_or_lazy;
52 pub mod higher;
53 mod hir_utils;
54 pub mod macros;
55 pub mod mir;
56 pub mod msrvs;
57 pub mod numeric_literal;
58 pub mod paths;
59 pub mod ptr;
60 pub mod qualify_min_const_fn;
61 pub mod source;
62 pub mod str_utils;
63 pub mod sugg;
64 pub mod ty;
65 pub mod usage;
66 pub mod visitors;
67 
68 pub use self::attrs::*;
69 pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
70 pub use self::hir_utils::{
71     both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
72 };
73 
74 use core::ops::ControlFlow;
75 use std::collections::hash_map::Entry;
76 use std::hash::BuildHasherDefault;
77 use std::sync::OnceLock;
78 use std::sync::{Mutex, MutexGuard};
79 
80 use if_chain::if_chain;
81 use itertools::Itertools;
82 use rustc_ast::ast::{self, LitKind, RangeLimits};
83 use rustc_ast::Attribute;
84 use rustc_data_structures::fx::FxHashMap;
85 use rustc_data_structures::unhash::UnhashMap;
86 use rustc_hir::def::{DefKind, Res};
87 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
88 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
89 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
90 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
91 use rustc_hir::{
92     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
93     ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
94     MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
95     TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
96 };
97 use rustc_lexer::{tokenize, TokenKind};
98 use rustc_lint::{LateContext, Level, Lint, LintContext};
99 use rustc_middle::hir::place::PlaceBase;
100 use rustc_middle::mir::ConstantKind;
101 use rustc_middle::ty as rustc_ty;
102 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
103 use rustc_middle::ty::binding::BindingMode;
104 use rustc_middle::ty::fast_reject::SimplifiedType::{
105     ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
106     PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
107 };
108 use rustc_middle::ty::{
109     layout::IntegerExt, BorrowKind, ClosureKind, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture,
110 };
111 use rustc_middle::ty::{FloatTy, IntTy, UintTy};
112 use rustc_span::hygiene::{ExpnKind, MacroKind};
113 use rustc_span::source_map::SourceMap;
114 use rustc_span::sym;
115 use rustc_span::symbol::{kw, Ident, Symbol};
116 use rustc_span::Span;
117 use rustc_target::abi::Integer;
118 
119 use crate::consts::{constant, miri_to_const, Constant};
120 use crate::higher::Range;
121 use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
122 use crate::visitors::for_each_expr;
123 
124 use rustc_middle::hir::nested_filter;
125 
126 #[macro_export]
127 macro_rules! extract_msrv_attr {
128     ($context:ident) => {
129         fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
130             let sess = rustc_lint::LintContext::sess(cx);
131             self.msrv.enter_lint_attrs(sess, attrs);
132         }
133 
134         fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
135             let sess = rustc_lint::LintContext::sess(cx);
136             self.msrv.exit_lint_attrs(sess, attrs);
137         }
138     };
139 }
140 
141 /// If the given expression is a local binding, find the initializer expression.
142 /// If that initializer expression is another local binding, find its initializer again.
143 /// This process repeats as long as possible (but usually no more than once). Initializer
144 /// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
145 /// instead.
146 ///
147 /// Examples:
148 /// ```
149 /// let abc = 1;
150 /// //        ^ output
151 /// let def = abc;
152 /// dbg!(def);
153 /// //   ^^^ input
154 ///
155 /// // or...
156 /// let abc = 1;
157 /// let def = abc + 2;
158 /// //        ^^^^^^^ output
159 /// dbg!(def);
160 /// //   ^^^ input
161 /// ```
expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b>162 pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
163     while let Some(init) = path_to_local(expr)
164         .and_then(|id| find_binding_init(cx, id))
165         .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
166     {
167         expr = init;
168     }
169     expr
170 }
171 
172 /// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
173 /// By only considering immutable bindings, we guarantee that the returned expression represents the
174 /// value of the binding wherever it is referenced.
175 ///
176 /// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
177 /// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
178 /// canonical binding `HirId`.
find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>>179 pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
180     let hir = cx.tcx.hir();
181     if_chain! {
182         if let Some(Node::Pat(pat)) = hir.find(hir_id);
183         if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
184         let parent = hir.parent_id(hir_id);
185         if let Some(Node::Local(local)) = hir.find(parent);
186         then {
187             return local.init;
188         }
189     }
190     None
191 }
192 
193 /// Returns `true` if the given `NodeId` is inside a constant context
194 ///
195 /// # Example
196 ///
197 /// ```rust,ignore
198 /// if in_constant(cx, expr.hir_id) {
199 ///     // Do something
200 /// }
201 /// ```
in_constant(cx: &LateContext<'_>, id: HirId) -> bool202 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
203     cx.tcx.hir().is_inside_const_context(id)
204 }
205 
206 /// Checks if a `Res` refers to a constructor of a `LangItem`
207 /// For example, use this to check whether a function call or a pattern is `Some(..)`.
is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool208 pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
209     if let Res::Def(DefKind::Ctor(..), id) = res
210         && let Some(lang_id) = cx.tcx.lang_items().get(lang_item)
211         && let Some(id) = cx.tcx.opt_parent(id)
212     {
213         id == lang_id
214     } else {
215         false
216     }
217 }
218 
is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool219 pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool {
220     if let Res::Def(DefKind::Ctor(..), id) = res
221         && let Some(id) = cx.tcx.opt_parent(id)
222     {
223         cx.tcx.is_diagnostic_item(diag_item, id)
224     } else {
225         false
226     }
227 }
228 
229 /// Checks if a `QPath` resolves to a constructor of a diagnostic item.
is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool230 pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool {
231     if let QPath::Resolved(_, path) = qpath {
232         if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
233             return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id));
234         }
235     }
236     false
237 }
238 
239 /// Checks if the `DefId` matches the given diagnostic item or it's constructor.
is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool240 pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool {
241     let did = match cx.tcx.def_kind(did) {
242         DefKind::Ctor(..) => cx.tcx.parent(did),
243         // Constructors for types in external crates seem to have `DefKind::Variant`
244         DefKind::Variant => match cx.tcx.opt_parent(did) {
245             Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
246             _ => did,
247         },
248         _ => did,
249     };
250 
251     cx.tcx.is_diagnostic_item(item, did)
252 }
253 
254 /// Checks if the `DefId` matches the given `LangItem` or it's constructor.
is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool255 pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool {
256     let did = match cx.tcx.def_kind(did) {
257         DefKind::Ctor(..) => cx.tcx.parent(did),
258         // Constructors for types in external crates seem to have `DefKind::Variant`
259         DefKind::Variant => match cx.tcx.opt_parent(did) {
260             Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
261             _ => did,
262         },
263         _ => did,
264     };
265 
266     cx.tcx.lang_items().get(item) == Some(did)
267 }
268 
is_unit_expr(expr: &Expr<'_>) -> bool269 pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
270     matches!(
271         expr.kind,
272         ExprKind::Block(
273             Block {
274                 stmts: [],
275                 expr: None,
276                 ..
277             },
278             _
279         ) | ExprKind::Tup([])
280     )
281 }
282 
283 /// Checks if given pattern is a wildcard (`_`)
is_wild(pat: &Pat<'_>) -> bool284 pub fn is_wild(pat: &Pat<'_>) -> bool {
285     matches!(pat.kind, PatKind::Wild)
286 }
287 
288 /// Checks if the given `QPath` belongs to a type alias.
is_ty_alias(qpath: &QPath<'_>) -> bool289 pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
290     match *qpath {
291         QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
292         QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
293         _ => false,
294     }
295 }
296 
297 /// Checks if the method call given in `expr` belongs to the given trait.
298 /// This is a deprecated function, consider using [`is_trait_method`].
match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool299 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
300     let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
301     let trt_id = cx.tcx.trait_of_item(def_id);
302     trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
303 }
304 
305 /// Checks if a method is defined in an impl of a diagnostic item
is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool306 pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
307     if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
308         if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
309             return cx.tcx.is_diagnostic_item(diag_item, adt.did());
310         }
311     }
312     false
313 }
314 
315 /// Checks if a method is in a diagnostic item trait
is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool316 pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
317     if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
318         return cx.tcx.is_diagnostic_item(diag_item, trait_did);
319     }
320     false
321 }
322 
323 /// Checks if the method call given in `expr` belongs to the given trait.
is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool324 pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
325     cx.typeck_results()
326         .type_dependent_def_id(expr.hir_id)
327         .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
328 }
329 
330 /// Checks if the `def_id` belongs to a function that is part of a trait impl.
is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool331 pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
332     if let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(def_id)
333         && let Node::Item(item) = cx.tcx.hir().get_parent(hir_id)
334         && let ItemKind::Impl(imp) = item.kind
335     {
336         imp.of_trait.is_some()
337     } else {
338         false
339     }
340 }
341 
342 /// Checks if the given expression is a path referring an item on the trait
343 /// that is marked with the given diagnostic item.
344 ///
345 /// For checking method call expressions instead of path expressions, use
346 /// [`is_trait_method`].
347 ///
348 /// For example, this can be used to find if an expression like `u64::default`
349 /// refers to an item of the trait `Default`, which is associated with the
350 /// `diag_item` of `sym::Default`.
is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool351 pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
352     if let hir::ExprKind::Path(ref qpath) = expr.kind {
353         cx.qpath_res(qpath, expr.hir_id)
354             .opt_def_id()
355             .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
356     } else {
357         false
358     }
359 }
360 
last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx>361 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
362     match *path {
363         QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
364         QPath::TypeRelative(_, seg) => seg,
365         QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
366     }
367 }
368 
qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>>369 pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
370     last_path_segment(qpath)
371         .args
372         .map_or(&[][..], |a| a.args)
373         .iter()
374         .filter_map(|a| match a {
375             hir::GenericArg::Type(ty) => Some(*ty),
376             _ => None,
377         })
378 }
379 
380 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
381 /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
382 /// `QPath::Resolved.1.res.opt_def_id()`.
383 ///
384 /// Matches a `QPath` against a slice of segment string literals.
385 ///
386 /// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
387 /// `rustc_hir::QPath`.
388 ///
389 /// # Examples
390 /// ```rust,ignore
391 /// match_qpath(path, &["std", "rt", "begin_unwind"])
392 /// ```
match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool393 pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
394     match *path {
395         QPath::Resolved(_, path) => match_path(path, segments),
396         QPath::TypeRelative(ty, segment) => match ty.kind {
397             TyKind::Path(ref inner_path) => {
398                 if let [prefix @ .., end] = segments {
399                     if match_qpath(inner_path, prefix) {
400                         return segment.ident.name.as_str() == *end;
401                     }
402                 }
403                 false
404             },
405             _ => false,
406         },
407         QPath::LangItem(..) => false,
408     }
409 }
410 
411 /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
412 ///
413 /// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool414 pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
415     path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
416 }
417 
418 /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
419 /// it matches the given lang item.
is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool420 pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool {
421     path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id))
422 }
423 
424 /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
425 /// it matches the given diagnostic item.
is_path_diagnostic_item<'tcx>( cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, diag_item: Symbol, ) -> bool426 pub fn is_path_diagnostic_item<'tcx>(
427     cx: &LateContext<'_>,
428     maybe_path: &impl MaybePath<'tcx>,
429     diag_item: Symbol,
430 ) -> bool {
431     path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
432 }
433 
434 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
435 /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
436 /// `QPath::Resolved.1.res.opt_def_id()`.
437 ///
438 /// Matches a `Path` against a slice of segment string literals.
439 ///
440 /// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
441 /// `rustc_hir::Path`.
442 ///
443 /// # Examples
444 ///
445 /// ```rust,ignore
446 /// if match_path(&trait_ref.path, &paths::HASH) {
447 ///     // This is the `std::hash::Hash` trait.
448 /// }
449 ///
450 /// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
451 ///     // This is a `rustc_middle::lint::Lint`.
452 /// }
453 /// ```
match_path(path: &Path<'_>, segments: &[&str]) -> bool454 pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
455     path.segments
456         .iter()
457         .rev()
458         .zip(segments.iter().rev())
459         .all(|(a, b)| a.ident.name.as_str() == *b)
460 }
461 
462 /// If the expression is a path to a local, returns the canonical `HirId` of the local.
path_to_local(expr: &Expr<'_>) -> Option<HirId>463 pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
464     if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
465         if let Res::Local(id) = path.res {
466             return Some(id);
467         }
468     }
469     None
470 }
471 
472 /// Returns true if the expression is a path to a local with the specified `HirId`.
473 /// Use this function to see if an expression matches a function argument or a match binding.
path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool474 pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
475     path_to_local(expr) == Some(id)
476 }
477 
478 pub trait MaybePath<'hir> {
hir_id(&self) -> HirId479     fn hir_id(&self) -> HirId;
qpath_opt(&self) -> Option<&QPath<'hir>>480     fn qpath_opt(&self) -> Option<&QPath<'hir>>;
481 }
482 
483 macro_rules! maybe_path {
484     ($ty:ident, $kind:ident) => {
485         impl<'hir> MaybePath<'hir> for hir::$ty<'hir> {
486             fn hir_id(&self) -> HirId {
487                 self.hir_id
488             }
489             fn qpath_opt(&self) -> Option<&QPath<'hir>> {
490                 match &self.kind {
491                     hir::$kind::Path(qpath) => Some(qpath),
492                     _ => None,
493                 }
494             }
495         }
496     };
497 }
498 maybe_path!(Expr, ExprKind);
499 maybe_path!(Pat, PatKind);
500 maybe_path!(Ty, TyKind);
501 
502 /// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res503 pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res {
504     match maybe_path.qpath_opt() {
505         None => Res::Err,
506         Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()),
507     }
508 }
509 
510 /// If `maybe_path` is a path node which resolves to an item, retrieves the item ID
path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId>511 pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId> {
512     path_res(cx, maybe_path).opt_def_id()
513 }
514 
find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx515 fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
516     let ty = match name {
517         "bool" => BoolSimplifiedType,
518         "char" => CharSimplifiedType,
519         "str" => StrSimplifiedType,
520         "array" => ArraySimplifiedType,
521         "slice" => SliceSimplifiedType,
522         // FIXME: rustdoc documents these two using just `pointer`.
523         //
524         // Maybe this is something we should do here too.
525         "const_ptr" => PtrSimplifiedType(Mutability::Not),
526         "mut_ptr" => PtrSimplifiedType(Mutability::Mut),
527         "isize" => IntSimplifiedType(IntTy::Isize),
528         "i8" => IntSimplifiedType(IntTy::I8),
529         "i16" => IntSimplifiedType(IntTy::I16),
530         "i32" => IntSimplifiedType(IntTy::I32),
531         "i64" => IntSimplifiedType(IntTy::I64),
532         "i128" => IntSimplifiedType(IntTy::I128),
533         "usize" => UintSimplifiedType(UintTy::Usize),
534         "u8" => UintSimplifiedType(UintTy::U8),
535         "u16" => UintSimplifiedType(UintTy::U16),
536         "u32" => UintSimplifiedType(UintTy::U32),
537         "u64" => UintSimplifiedType(UintTy::U64),
538         "u128" => UintSimplifiedType(UintTy::U128),
539         "f32" => FloatSimplifiedType(FloatTy::F32),
540         "f64" => FloatSimplifiedType(FloatTy::F64),
541         _ => return [].iter().copied(),
542     };
543 
544     tcx.incoherent_impls(ty).iter().copied()
545 }
546 
non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res>547 fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
548     match tcx.def_kind(def_id) {
549         DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
550             .module_children(def_id)
551             .iter()
552             .filter(|item| item.ident.name == name)
553             .map(|child| child.res.expect_non_local())
554             .collect(),
555         DefKind::Impl { .. } => tcx
556             .associated_item_def_ids(def_id)
557             .iter()
558             .copied()
559             .filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
560             .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
561             .collect(),
562         _ => Vec::new(),
563     }
564 }
565 
local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res>566 fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
567     let hir = tcx.hir();
568 
569     let root_mod;
570     let item_kind = match hir.find_by_def_id(local_id) {
571         Some(Node::Crate(r#mod)) => {
572             root_mod = ItemKind::Mod(r#mod);
573             &root_mod
574         },
575         Some(Node::Item(item)) => &item.kind,
576         _ => return Vec::new(),
577     };
578 
579     let res = |ident: Ident, owner_id: OwnerId| {
580         if ident.name == name {
581             let def_id = owner_id.to_def_id();
582             Some(Res::Def(tcx.def_kind(def_id), def_id))
583         } else {
584             None
585         }
586     };
587 
588     match item_kind {
589         ItemKind::Mod(r#mod) => r#mod
590             .item_ids
591             .iter()
592             .filter_map(|&item_id| res(hir.item(item_id).ident, item_id.owner_id))
593             .collect(),
594         ItemKind::Impl(r#impl) => r#impl
595             .items
596             .iter()
597             .filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id))
598             .collect(),
599         ItemKind::Trait(.., trait_item_refs) => trait_item_refs
600             .iter()
601             .filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id))
602             .collect(),
603         _ => Vec::new(),
604     }
605 }
606 
item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res>607 fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
608     if let Some(local_id) = def_id.as_local() {
609         local_item_children_by_name(tcx, local_id, name)
610     } else {
611         non_local_item_children_by_name(tcx, def_id, name)
612     }
613 }
614 
615 /// Resolves a def path like `std::vec::Vec`.
616 ///
617 /// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
618 /// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
619 ///
620 /// Also returns multiple results when there are multiple paths under the same name e.g. `std::vec`
621 /// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
622 ///
623 /// This function is expensive and should be used sparingly.
def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res>624 pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> {
625     fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator<Item = DefId> + '_ {
626         tcx.crates(())
627             .iter()
628             .copied()
629             .filter(move |&num| tcx.crate_name(num) == name)
630             .map(CrateNum::as_def_id)
631     }
632 
633     let tcx = cx.tcx;
634 
635     let (base, mut path) = match *path {
636         [primitive] => {
637             return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
638         },
639         [base, ref path @ ..] => (base, path),
640         _ => return Vec::new(),
641     };
642 
643     let base_sym = Symbol::intern(base);
644 
645     let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
646         Some(LOCAL_CRATE.as_def_id())
647     } else {
648         None
649     };
650 
651     let starts = find_primitive_impls(tcx, base)
652         .chain(find_crates(tcx, base_sym))
653         .chain(local_crate)
654         .map(|id| Res::Def(tcx.def_kind(id), id));
655 
656     let mut resolutions: Vec<Res> = starts.collect();
657 
658     while let [segment, rest @ ..] = path {
659         path = rest;
660         let segment = Symbol::intern(segment);
661 
662         resolutions = resolutions
663             .into_iter()
664             .filter_map(|res| res.opt_def_id())
665             .flat_map(|def_id| {
666                 // When the current def_id is e.g. `struct S`, check the impl items in
667                 // `impl S { ... }`
668                 let inherent_impl_children = tcx
669                     .inherent_impls(def_id)
670                     .iter()
671                     .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
672 
673                 let direct_children = item_children_by_name(tcx, def_id, segment);
674 
675                 inherent_impl_children.chain(direct_children)
676             })
677             .collect();
678     }
679 
680     resolutions
681 }
682 
683 /// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`].
def_path_def_ids(cx: &LateContext<'_>, path: &[&str]) -> impl Iterator<Item = DefId>684 pub fn def_path_def_ids(cx: &LateContext<'_>, path: &[&str]) -> impl Iterator<Item = DefId> {
685     def_path_res(cx, path).into_iter().filter_map(|res| res.opt_def_id())
686 }
687 
688 /// Convenience function to get the `DefId` of a trait by path.
689 /// It could be a trait or trait alias.
690 ///
691 /// This function is expensive and should be used sparingly.
get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId>692 pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
693     def_path_res(cx, path).into_iter().find_map(|res| match res {
694         Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
695         _ => None,
696     })
697 }
698 
699 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
700 ///
701 /// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
702 ///
703 /// ```rust
704 /// struct Point(isize, isize);
705 ///
706 /// impl std::ops::Add for Point {
707 ///     type Output = Self;
708 ///
709 ///     fn add(self, other: Self) -> Self {
710 ///         Point(0, 0)
711 ///     }
712 /// }
713 /// ```
trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>>714 pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
715     // Get the implemented trait for the current function
716     let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
717     let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
718     if_chain! {
719         if parent_impl != hir::CRATE_OWNER_ID;
720         if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id);
721         if let hir::ItemKind::Impl(impl_) = &item.kind;
722         then {
723             return impl_.of_trait.as_ref();
724         }
725     }
726     None
727 }
728 
729 /// This method will return tuple of projection stack and root of the expression,
730 /// used in `can_mut_borrow_both`.
731 ///
732 /// For example, if `e` represents the `v[0].a.b[x]`
733 /// this method will return a tuple, composed of a `Vec`
734 /// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
735 /// and an `Expr` for root of them, `v`
projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>)736 fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
737     let mut result = vec![];
738     let root = loop {
739         match e.kind {
740             ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
741                 result.push(e);
742                 e = ep;
743             },
744             _ => break e,
745         };
746     };
747     result.reverse();
748     (result, root)
749 }
750 
751 /// Gets the mutability of the custom deref adjustment, if any.
expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability>752 pub fn expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability> {
753     cx.typeck_results()
754         .expr_adjustments(e)
755         .iter()
756         .find_map(|a| match a.kind {
757             Adjust::Deref(Some(d)) => Some(Some(d.mutbl)),
758             Adjust::Deref(None) => None,
759             _ => Some(None),
760         })
761         .and_then(|x| x)
762 }
763 
764 /// Checks if two expressions can be mutably borrowed simultaneously
765 /// and they aren't dependent on borrowing same thing twice
can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool766 pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
767     let (s1, r1) = projection_stack(e1);
768     let (s2, r2) = projection_stack(e2);
769     if !eq_expr_value(cx, r1, r2) {
770         return true;
771     }
772     if expr_custom_deref_adjustment(cx, r1).is_some() || expr_custom_deref_adjustment(cx, r2).is_some() {
773         return false;
774     }
775 
776     for (x1, x2) in s1.iter().zip(s2.iter()) {
777         if expr_custom_deref_adjustment(cx, x1).is_some() || expr_custom_deref_adjustment(cx, x2).is_some() {
778             return false;
779         }
780 
781         match (&x1.kind, &x2.kind) {
782             (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
783                 if i1 != i2 {
784                     return true;
785                 }
786             },
787             (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
788                 if !eq_expr_value(cx, i1, i2) {
789                     return false;
790                 }
791             },
792             _ => return false,
793         }
794     }
795     false
796 }
797 
798 /// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
799 /// constructor from the std library
is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool800 fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
801     let std_types_symbols = &[
802         sym::Vec,
803         sym::VecDeque,
804         sym::LinkedList,
805         sym::HashMap,
806         sym::BTreeMap,
807         sym::HashSet,
808         sym::BTreeSet,
809         sym::BinaryHeap,
810     ];
811 
812     if let QPath::TypeRelative(_, method) = path {
813         if method.ident.name == sym::new {
814             if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
815                 if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
816                     return std_types_symbols.iter().any(|&symbol| {
817                         cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
818                     });
819                 }
820             }
821         }
822     }
823     false
824 }
825 
826 /// Return true if the expr is equal to `Default::default` when evaluated.
is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool827 pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
828     if_chain! {
829         if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
830         if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
831         if is_diag_trait_item(cx, repl_def_id, sym::Default)
832             || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
833         then { true } else { false }
834     }
835 }
836 
837 /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
838 /// It doesn't cover all cases, for example indirect function calls (some of std
839 /// functions are supported) but it is the best we have.
is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool840 pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
841     match &e.kind {
842         ExprKind::Lit(lit) => match lit.node {
843             LitKind::Bool(false) | LitKind::Int(0, _) => true,
844             LitKind::Str(s, _) => s.is_empty(),
845             _ => false,
846         },
847         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
848         ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
849             if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind;
850             if let LitKind::Int(v, _) = const_lit.node;
851             if v <= 32 && is_default_equivalent(cx, x);
852             then {
853                 true
854             }
855             else {
856                 false
857             }
858         },
859         ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func),
860         ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg),
861         ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
862         ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
863         _ => false,
864     }
865 }
866 
is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool867 fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {
868     if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind &&
869         seg.ident.name == sym::from
870     {
871         match arg.kind {
872             ExprKind::Lit(hir::Lit {
873                 node: LitKind::Str(ref sym, _),
874                 ..
875             }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
876             ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
877             ExprKind::Repeat(_, ArrayLen::Body(len)) => {
878                 if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind &&
879                     let LitKind::Int(v, _) = const_lit.node
880                 {
881                         return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
882                 }
883             }
884             _ => (),
885         }
886     }
887     false
888 }
889 
890 /// Checks if the top level expression can be moved into a closure as is.
891 /// Currently checks for:
892 /// * Break/Continue outside the given loop HIR ids.
893 /// * Yield/Return statements.
894 /// * Inline assembly.
895 /// * Usages of a field of a local where the type of the local can be partially moved.
896 ///
897 /// For example, given the following function:
898 ///
899 /// ```
900 /// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
901 ///     for item in iter {
902 ///         let s = item.1;
903 ///         if item.0 > 10 {
904 ///             continue;
905 ///         } else {
906 ///             s.clear();
907 ///         }
908 ///     }
909 /// }
910 /// ```
911 ///
912 /// When called on the expression `item.0` this will return false unless the local `item` is in the
913 /// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it
914 /// isn't always safe to move into a closure when only a single field is needed.
915 ///
916 /// When called on the `continue` expression this will return false unless the outer loop expression
917 /// is in the `loop_ids` set.
918 ///
919 /// Note that this check is not recursive, so passing the `if` expression will always return true
920 /// even though sub-expressions might return false.
can_move_expr_to_closure_no_visit<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_ids: &[HirId], ignore_locals: &HirIdSet, ) -> bool921 pub fn can_move_expr_to_closure_no_visit<'tcx>(
922     cx: &LateContext<'tcx>,
923     expr: &'tcx Expr<'_>,
924     loop_ids: &[HirId],
925     ignore_locals: &HirIdSet,
926 ) -> bool {
927     match expr.kind {
928         ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
929         | ExprKind::Continue(Destination { target_id: Ok(id), .. })
930             if loop_ids.contains(&id) =>
931         {
932             true
933         },
934         ExprKind::Break(..)
935         | ExprKind::Continue(_)
936         | ExprKind::Ret(_)
937         | ExprKind::Yield(..)
938         | ExprKind::InlineAsm(_) => false,
939         // Accessing a field of a local value can only be done if the type isn't
940         // partially moved.
941         ExprKind::Field(
942             &Expr {
943                 hir_id,
944                 kind:
945                     ExprKind::Path(QPath::Resolved(
946                         _,
947                         Path {
948                             res: Res::Local(local_id),
949                             ..
950                         },
951                     )),
952                 ..
953             },
954             _,
955         ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {
956             // TODO: check if the local has been partially moved. Assume it has for now.
957             false
958         },
959         _ => true,
960     }
961 }
962 
963 /// How a local is captured by a closure
964 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
965 pub enum CaptureKind {
966     Value,
967     Ref(Mutability),
968 }
969 impl CaptureKind {
is_imm_ref(self) -> bool970     pub fn is_imm_ref(self) -> bool {
971         self == Self::Ref(Mutability::Not)
972     }
973 }
974 impl std::ops::BitOr for CaptureKind {
975     type Output = Self;
bitor(self, rhs: Self) -> Self::Output976     fn bitor(self, rhs: Self) -> Self::Output {
977         match (self, rhs) {
978             (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
979             (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
980             | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
981             (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
982         }
983     }
984 }
985 impl std::ops::BitOrAssign for CaptureKind {
bitor_assign(&mut self, rhs: Self)986     fn bitor_assign(&mut self, rhs: Self) {
987         *self = *self | rhs;
988     }
989 }
990 
991 /// Given an expression referencing a local, determines how it would be captured in a closure.
992 /// Note as this will walk up to parent expressions until the capture can be determined it should
993 /// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
994 /// function argument (other than a receiver).
capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind995 pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
996     fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
997         let mut capture = CaptureKind::Ref(Mutability::Not);
998         pat.each_binding_or_first(&mut |_, id, span, _| match cx
999             .typeck_results()
1000             .extract_binding_mode(cx.sess(), id, span)
1001             .unwrap()
1002         {
1003             BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
1004                 capture = CaptureKind::Value;
1005             },
1006             BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
1007                 capture = CaptureKind::Ref(Mutability::Mut);
1008             },
1009             _ => (),
1010         });
1011         capture
1012     }
1013 
1014     debug_assert!(matches!(
1015         e.kind,
1016         ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))
1017     ));
1018 
1019     let mut child_id = e.hir_id;
1020     let mut capture = CaptureKind::Value;
1021     let mut capture_expr_ty = e;
1022 
1023     for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
1024         if let [
1025             Adjustment {
1026                 kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
1027                 target,
1028             },
1029             ref adjust @ ..,
1030         ] = *cx
1031             .typeck_results()
1032             .adjustments()
1033             .get(child_id)
1034             .map_or(&[][..], |x| &**x)
1035         {
1036             if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) =
1037                 *adjust.last().map_or(target, |a| a.target).kind()
1038             {
1039                 return CaptureKind::Ref(mutability);
1040             }
1041         }
1042 
1043         match parent {
1044             Node::Expr(e) => match e.kind {
1045                 ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),
1046                 ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),
1047                 ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {
1048                     return CaptureKind::Ref(Mutability::Mut);
1049                 },
1050                 ExprKind::Field(..) => {
1051                     if capture == CaptureKind::Value {
1052                         capture_expr_ty = e;
1053                     }
1054                 },
1055                 ExprKind::Let(let_expr) => {
1056                     let mutability = match pat_capture_kind(cx, let_expr.pat) {
1057                         CaptureKind::Value => Mutability::Not,
1058                         CaptureKind::Ref(m) => m,
1059                     };
1060                     return CaptureKind::Ref(mutability);
1061                 },
1062                 ExprKind::Match(_, arms, _) => {
1063                     let mut mutability = Mutability::Not;
1064                     for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
1065                         match capture {
1066                             CaptureKind::Value => break,
1067                             CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
1068                             CaptureKind::Ref(Mutability::Not) => (),
1069                         }
1070                     }
1071                     return CaptureKind::Ref(mutability);
1072                 },
1073                 _ => break,
1074             },
1075             Node::Local(l) => match pat_capture_kind(cx, l.pat) {
1076                 CaptureKind::Value => break,
1077                 capture @ CaptureKind::Ref(_) => return capture,
1078             },
1079             _ => break,
1080         }
1081 
1082         child_id = parent_id;
1083     }
1084 
1085     if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {
1086         // Copy types are never automatically captured by value.
1087         CaptureKind::Ref(Mutability::Not)
1088     } else {
1089         capture
1090     }
1091 }
1092 
1093 /// Checks if the expression can be moved into a closure as is. This will return a list of captures
1094 /// if so, otherwise, `None`.
can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>>1095 pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
1096     struct V<'cx, 'tcx> {
1097         cx: &'cx LateContext<'tcx>,
1098         // Stack of potential break targets contained in the expression.
1099         loops: Vec<HirId>,
1100         /// Local variables created in the expression. These don't need to be captured.
1101         locals: HirIdSet,
1102         /// Whether this expression can be turned into a closure.
1103         allow_closure: bool,
1104         /// Locals which need to be captured, and whether they need to be by value, reference, or
1105         /// mutable reference.
1106         captures: HirIdMap<CaptureKind>,
1107     }
1108     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
1109         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
1110             if !self.allow_closure {
1111                 return;
1112             }
1113 
1114             match e.kind {
1115                 ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {
1116                     if !self.locals.contains(&l) {
1117                         let cap = capture_local_usage(self.cx, e);
1118                         self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
1119                     }
1120                 },
1121                 ExprKind::Closure(closure) => {
1122                     for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) {
1123                         let local_id = match capture.place.base {
1124                             PlaceBase::Local(id) => id,
1125                             PlaceBase::Upvar(var) => var.var_path.hir_id,
1126                             _ => continue,
1127                         };
1128                         if !self.locals.contains(&local_id) {
1129                             let capture = match capture.info.capture_kind {
1130                                 UpvarCapture::ByValue => CaptureKind::Value,
1131                                 UpvarCapture::ByRef(kind) => match kind {
1132                                     BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
1133                                     BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
1134                                         CaptureKind::Ref(Mutability::Mut)
1135                                     },
1136                                 },
1137                             };
1138                             self.captures
1139                                 .entry(local_id)
1140                                 .and_modify(|e| *e |= capture)
1141                                 .or_insert(capture);
1142                         }
1143                     }
1144                 },
1145                 ExprKind::Loop(b, ..) => {
1146                     self.loops.push(e.hir_id);
1147                     self.visit_block(b);
1148                     self.loops.pop();
1149                 },
1150                 _ => {
1151                     self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);
1152                     walk_expr(self, e);
1153                 },
1154             }
1155         }
1156 
1157         fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
1158             p.each_binding_or_first(&mut |_, id, _, _| {
1159                 self.locals.insert(id);
1160             });
1161         }
1162     }
1163 
1164     let mut v = V {
1165         cx,
1166         allow_closure: true,
1167         loops: Vec::new(),
1168         locals: HirIdSet::default(),
1169         captures: HirIdMap::default(),
1170     };
1171     v.visit_expr(expr);
1172     v.allow_closure.then_some(v.captures)
1173 }
1174 
1175 /// Arguments of a method: the receiver and all the additional arguments.
1176 pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;
1177 
1178 /// Returns the method names and argument list of nested method call expressions that make up
1179 /// `expr`. method/span lists are sorted with the most recent call first.
method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>)1180 pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {
1181     let mut method_names = Vec::with_capacity(max_depth);
1182     let mut arg_lists = Vec::with_capacity(max_depth);
1183     let mut spans = Vec::with_capacity(max_depth);
1184 
1185     let mut current = expr;
1186     for _ in 0..max_depth {
1187         if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
1188             if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
1189                 break;
1190             }
1191             method_names.push(path.ident.name);
1192             arg_lists.push((*receiver, &**args));
1193             spans.push(path.ident.span);
1194             current = receiver;
1195         } else {
1196             break;
1197         }
1198     }
1199 
1200     (method_names, arg_lists, spans)
1201 }
1202 
1203 /// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
1204 ///
1205 /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
1206 /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
1207 /// containing the `Expr`s for
1208 /// `.bar()` and `.baz()`
method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>>1209 pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
1210     let mut current = expr;
1211     let mut matched = Vec::with_capacity(methods.len());
1212     for method_name in methods.iter().rev() {
1213         // method chains are stored last -> first
1214         if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
1215             if path.ident.name.as_str() == *method_name {
1216                 if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
1217                     return None;
1218                 }
1219                 matched.push((receiver, args)); // build up `matched` backwards
1220                 current = receiver; // go to parent expression
1221             } else {
1222                 return None;
1223             }
1224         } else {
1225             return None;
1226         }
1227     }
1228     // Reverse `matched` so that it is in the same order as `methods`.
1229     matched.reverse();
1230     Some(matched)
1231 }
1232 
1233 /// Returns `true` if the provided `def_id` is an entrypoint to a program.
is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool1234 pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
1235     cx.tcx
1236         .entry_fn(())
1237         .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
1238 }
1239 
1240 /// Returns `true` if the expression is in the program's `#[panic_handler]`.
is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool1241 pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
1242     let parent = cx.tcx.hir().get_parent_item(e.hir_id);
1243     Some(parent.to_def_id()) == cx.tcx.lang_items().panic_impl()
1244 }
1245 
1246 /// Gets the name of the item the expression is in, if available.
get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol>1247 pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
1248     let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
1249     match cx.tcx.hir().find_by_def_id(parent_id) {
1250         Some(
1251             Node::Item(Item { ident, .. })
1252             | Node::TraitItem(TraitItem { ident, .. })
1253             | Node::ImplItem(ImplItem { ident, .. }),
1254         ) => Some(ident.name),
1255         _ => None,
1256     }
1257 }
1258 
1259 pub struct ContainsName<'a, 'tcx> {
1260     pub cx: &'a LateContext<'tcx>,
1261     pub name: Symbol,
1262     pub result: bool,
1263 }
1264 
1265 impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> {
1266     type NestedFilter = nested_filter::OnlyBodies;
1267 
visit_name(&mut self, name: Symbol)1268     fn visit_name(&mut self, name: Symbol) {
1269         if self.name == name {
1270             self.result = true;
1271         }
1272     }
1273 
nested_visit_map(&mut self) -> Self::Map1274     fn nested_visit_map(&mut self) -> Self::Map {
1275         self.cx.tcx.hir()
1276     }
1277 }
1278 
1279 /// Checks if an `Expr` contains a certain name.
contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool1280 pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {
1281     let mut cn = ContainsName {
1282         name,
1283         result: false,
1284         cx,
1285     };
1286     cn.visit_expr(expr);
1287     cn.result
1288 }
1289 
1290 /// Returns `true` if `expr` contains a return expression
contains_return(expr: &hir::Expr<'_>) -> bool1291 pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
1292     for_each_expr(expr, |e| {
1293         if matches!(e.kind, hir::ExprKind::Ret(..)) {
1294             ControlFlow::Break(())
1295         } else {
1296             ControlFlow::Continue(())
1297         }
1298     })
1299     .is_some()
1300 }
1301 
1302 /// Gets the parent node, if any.
get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>>1303 pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
1304     tcx.hir().find_parent(id)
1305 }
1306 
1307 /// Gets the parent expression, if any –- this is useful to constrain a lint.
get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>>1308 pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
1309     get_parent_expr_for_hir(cx, e.hir_id)
1310 }
1311 
1312 /// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
1313 /// constraint lints
get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>>1314 pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
1315     match get_parent_node(cx.tcx, hir_id) {
1316         Some(Node::Expr(parent)) => Some(parent),
1317         _ => None,
1318     }
1319 }
1320 
1321 /// Gets the enclosing block, if any.
get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>>1322 pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
1323     let map = &cx.tcx.hir();
1324     let enclosing_node = map
1325         .get_enclosing_scope(hir_id)
1326         .and_then(|enclosing_id| map.find(enclosing_id));
1327     enclosing_node.and_then(|node| match node {
1328         Node::Block(block) => Some(block),
1329         Node::Item(&Item {
1330             kind: ItemKind::Fn(_, _, eid),
1331             ..
1332         })
1333         | Node::ImplItem(&ImplItem {
1334             kind: ImplItemKind::Fn(_, eid),
1335             ..
1336         }) => match cx.tcx.hir().body(eid).value.kind {
1337             ExprKind::Block(block, _) => Some(block),
1338             _ => None,
1339         },
1340         _ => None,
1341     })
1342 }
1343 
1344 /// Gets the loop or closure enclosing the given expression, if any.
get_enclosing_loop_or_multi_call_closure<'tcx>( cx: &LateContext<'tcx>, expr: &Expr<'_>, ) -> Option<&'tcx Expr<'tcx>>1345 pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
1346     cx: &LateContext<'tcx>,
1347     expr: &Expr<'_>,
1348 ) -> Option<&'tcx Expr<'tcx>> {
1349     for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
1350         match node {
1351             Node::Expr(e) => match e.kind {
1352                 ExprKind::Closure { .. } => {
1353                     if let rustc_ty::Closure(_, subs) = cx.typeck_results().expr_ty(e).kind()
1354                         && subs.as_closure().kind() == ClosureKind::FnOnce
1355                     {
1356                         continue;
1357                     }
1358                     let is_once = walk_to_expr_usage(cx, e, |node, id| {
1359                         let Node::Expr(e) = node else {
1360                             return None;
1361                         };
1362                         match e.kind {
1363                             ExprKind::Call(f, _) if f.hir_id == id => Some(()),
1364                             ExprKind::Call(f, args) => {
1365                                 let i = args.iter().position(|arg| arg.hir_id == id)?;
1366                                 let sig = expr_sig(cx, f)?;
1367                                 let predicates = sig
1368                                     .predicates_id()
1369                                     .map_or(cx.param_env, |id| cx.tcx.param_env(id))
1370                                     .caller_bounds();
1371                                 sig.input(i).and_then(|ty| {
1372                                     ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
1373                                 })
1374                             },
1375                             ExprKind::MethodCall(_, receiver, args, _) => {
1376                                 let i = std::iter::once(receiver)
1377                                     .chain(args.iter())
1378                                     .position(|arg| arg.hir_id == id)?;
1379                                 let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
1380                                 let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i];
1381                                 ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
1382                             },
1383                             _ => None,
1384                         }
1385                     })
1386                     .is_some();
1387                     if !is_once {
1388                         return Some(e);
1389                     }
1390                 },
1391                 ExprKind::Loop(..) => return Some(e),
1392                 _ => (),
1393             },
1394             Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
1395             _ => break,
1396         }
1397     }
1398     None
1399 }
1400 
1401 /// Gets the parent node if it's an impl block.
get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>>1402 pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
1403     match tcx.hir().parent_iter(id).next() {
1404         Some((
1405             _,
1406             Node::Item(Item {
1407                 kind: ItemKind::Impl(imp),
1408                 ..
1409             }),
1410         )) => Some(imp),
1411         _ => None,
1412     }
1413 }
1414 
1415 /// Removes blocks around an expression, only if the block contains just one expression
1416 /// and no statements. Unsafe blocks are not removed.
1417 ///
1418 /// Examples:
1419 ///  * `{}`               -> `{}`
1420 ///  * `{ x }`            -> `x`
1421 ///  * `{{ x }}`          -> `x`
1422 ///  * `{ x; }`           -> `{ x; }`
1423 ///  * `{ x; y }`         -> `{ x; y }`
1424 ///  * `{ unsafe { x } }` -> `unsafe { x }`
peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a>1425 pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
1426     while let ExprKind::Block(
1427         Block {
1428             stmts: [],
1429             expr: Some(inner),
1430             rules: BlockCheckMode::DefaultBlock,
1431             ..
1432         },
1433         _,
1434     ) = expr.kind
1435     {
1436         expr = inner;
1437     }
1438     expr
1439 }
1440 
1441 /// Removes blocks around an expression, only if the block contains just one expression
1442 /// or just one expression statement with a semicolon. Unsafe blocks are not removed.
1443 ///
1444 /// Examples:
1445 ///  * `{}`               -> `{}`
1446 ///  * `{ x }`            -> `x`
1447 ///  * `{ x; }`           -> `x`
1448 ///  * `{{ x; }}`         -> `x`
1449 ///  * `{ x; y }`         -> `{ x; y }`
1450 ///  * `{ unsafe { x } }` -> `unsafe { x }`
peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a>1451 pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
1452     while let ExprKind::Block(
1453         Block {
1454             stmts: [],
1455             expr: Some(inner),
1456             rules: BlockCheckMode::DefaultBlock,
1457             ..
1458         }
1459         | Block {
1460             stmts:
1461                 [
1462                     Stmt {
1463                         kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
1464                         ..
1465                     },
1466                 ],
1467             expr: None,
1468             rules: BlockCheckMode::DefaultBlock,
1469             ..
1470         },
1471         _,
1472     ) = expr.kind
1473     {
1474         expr = inner;
1475     }
1476     expr
1477 }
1478 
1479 /// Checks if the given expression is the else clause of either an `if` or `if let` expression.
is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool1480 pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1481     let mut iter = tcx.hir().parent_iter(expr.hir_id);
1482     match iter.next() {
1483         Some((
1484             _,
1485             Node::Expr(Expr {
1486                 kind: ExprKind::If(_, _, Some(else_expr)),
1487                 ..
1488             }),
1489         )) => else_expr.hir_id == expr.hir_id,
1490         _ => false,
1491     }
1492 }
1493 
1494 /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`.
1495 /// For the lower bound, this means that:
1496 /// - either there is none
1497 /// - or it is the smallest value that can be represented by the range's integer type
1498 /// For the upper bound, this means that:
1499 /// - either there is none
1500 /// - or it is the largest value that can be represented by the range's integer type and is
1501 ///   inclusive
1502 /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to
1503 ///   a method call on that same container (e.g. `v.drain(..v.len())`)
1504 /// If the given `Expr` is not some kind of range, the function returns `false`.
is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool1505 pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
1506     let ty = cx.typeck_results().expr_ty(expr);
1507     if let Some(Range { start, end, limits }) = Range::hir(expr) {
1508         let start_is_none_or_min = start.map_or(true, |start| {
1509             if let rustc_ty::Adt(_, subst) = ty.kind()
1510                 && let bnd_ty = subst.type_at(0)
1511                 && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
1512                 && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
1513                 && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
1514                 && let Some(min_const) = miri_to_const(cx, min_const_kind)
1515                 && let Some(start_const) = constant(cx, cx.typeck_results(), start)
1516             {
1517                 start_const == min_const
1518             } else {
1519                 false
1520             }
1521         });
1522         let end_is_none_or_max = end.map_or(true, |end| {
1523             match limits {
1524                 RangeLimits::Closed => {
1525                     if let rustc_ty::Adt(_, subst) = ty.kind()
1526                         && let bnd_ty = subst.type_at(0)
1527                         && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
1528                         && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
1529                         && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
1530                         && let Some(max_const) = miri_to_const(cx, max_const_kind)
1531                         && let Some(end_const) = constant(cx, cx.typeck_results(), end)
1532                     {
1533                         end_const == max_const
1534                     } else {
1535                         false
1536                     }
1537                 },
1538                 RangeLimits::HalfOpen => {
1539                     if let Some(container_path) = container_path
1540                         && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind
1541                         && name.ident.name == sym::len
1542                         && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
1543                     {
1544                         container_path.res == path.res
1545                     } else {
1546                         false
1547                     }
1548                 },
1549             }
1550         });
1551         return start_is_none_or_min && end_is_none_or_max;
1552     }
1553     false
1554 }
1555 
1556 /// Checks whether the given expression is a constant integer of the given value.
1557 /// unlike `is_integer_literal`, this version does const folding
is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool1558 pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
1559     if is_integer_literal(e, value) {
1560         return true;
1561     }
1562     let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
1563     if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
1564         return value == v;
1565     }
1566     false
1567 }
1568 
1569 /// Checks whether the given expression is a constant literal of the given value.
is_integer_literal(expr: &Expr<'_>, value: u128) -> bool1570 pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
1571     // FIXME: use constant folding
1572     if let ExprKind::Lit(spanned) = expr.kind {
1573         if let LitKind::Int(v, _) = spanned.node {
1574             return v == value;
1575         }
1576     }
1577     false
1578 }
1579 
1580 /// Returns `true` if the given `Expr` has been coerced before.
1581 ///
1582 /// Examples of coercions can be found in the Nomicon at
1583 /// <https://doc.rust-lang.org/nomicon/coercions.html>.
1584 ///
1585 /// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::check::coercion` for
1586 /// more information on adjustments and coercions.
is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool1587 pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
1588     cx.typeck_results().adjustments().get(e.hir_id).is_some()
1589 }
1590 
1591 /// Returns the pre-expansion span if this comes from an expansion of the
1592 /// macro `name`.
1593 /// See also [`is_direct_expn_of`].
1594 #[must_use]
is_expn_of(mut span: Span, name: &str) -> Option<Span>1595 pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
1596     loop {
1597         if span.from_expansion() {
1598             let data = span.ctxt().outer_expn_data();
1599             let new_span = data.call_site;
1600 
1601             if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
1602                 if mac_name.as_str() == name {
1603                     return Some(new_span);
1604                 }
1605             }
1606 
1607             span = new_span;
1608         } else {
1609             return None;
1610         }
1611     }
1612 }
1613 
1614 /// Returns the pre-expansion span if the span directly comes from an expansion
1615 /// of the macro `name`.
1616 /// The difference with [`is_expn_of`] is that in
1617 /// ```rust
1618 /// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
1619 /// # macro_rules! bar { ($e:expr) => { $e } }
1620 /// foo!(bar!(42));
1621 /// ```
1622 /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
1623 /// from `bar!` by `is_direct_expn_of`.
1624 #[must_use]
is_direct_expn_of(span: Span, name: &str) -> Option<Span>1625 pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
1626     if span.from_expansion() {
1627         let data = span.ctxt().outer_expn_data();
1628         let new_span = data.call_site;
1629 
1630         if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
1631             if mac_name.as_str() == name {
1632                 return Some(new_span);
1633             }
1634         }
1635     }
1636 
1637     None
1638 }
1639 
1640 /// Convenience function to get the return type of a function.
return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx>1641 pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
1642     let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output();
1643     cx.tcx.erase_late_bound_regions(ret_ty)
1644 }
1645 
1646 /// Convenience function to get the nth argument type of a function.
nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx>1647 pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
1648     let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth);
1649     cx.tcx.erase_late_bound_regions(arg)
1650 }
1651 
1652 /// Checks if an expression is constructing a tuple-like enum variant or struct
is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool1653 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1654     if let ExprKind::Call(fun, _) = expr.kind {
1655         if let ExprKind::Path(ref qp) = fun.kind {
1656             let res = cx.qpath_res(qp, fun.hir_id);
1657             return match res {
1658                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
1659                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
1660                 _ => false,
1661             };
1662         }
1663     }
1664     false
1665 }
1666 
1667 /// Returns `true` if a pattern is refutable.
1668 // TODO: should be implemented using rustc/mir_build/thir machinery
is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool1669 pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
1670     fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
1671         matches!(
1672             cx.qpath_res(qpath, id),
1673             def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
1674         )
1675     }
1676 
1677     fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
1678         i.into_iter().any(|pat| is_refutable(cx, pat))
1679     }
1680 
1681     match pat.kind {
1682         PatKind::Wild => false,
1683         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
1684         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
1685         PatKind::Lit(..) | PatKind::Range(..) => true,
1686         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
1687         PatKind::Or(pats) => {
1688             // TODO: should be the honest check, that pats is exhaustive set
1689             are_refutable(cx, pats)
1690         },
1691         PatKind::Tuple(pats, _) => are_refutable(cx, pats),
1692         PatKind::Struct(ref qpath, fields, _) => {
1693             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))
1694         },
1695         PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
1696         PatKind::Slice(head, middle, tail) => {
1697             match &cx.typeck_results().node_type(pat.hir_id).kind() {
1698                 rustc_ty::Slice(..) => {
1699                     // [..] is the only irrefutable slice pattern.
1700                     !head.is_empty() || middle.is_none() || !tail.is_empty()
1701                 },
1702                 rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
1703                 _ => {
1704                     // unreachable!()
1705                     true
1706                 },
1707             }
1708         },
1709     }
1710 }
1711 
1712 /// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
1713 /// the function once on the given pattern.
recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F)1714 pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
1715     if let PatKind::Or(pats) = pat.kind {
1716         pats.iter().for_each(f);
1717     } else {
1718         f(pat);
1719     }
1720 }
1721 
is_self(slf: &Param<'_>) -> bool1722 pub fn is_self(slf: &Param<'_>) -> bool {
1723     if let PatKind::Binding(.., name, _) = slf.pat.kind {
1724         name.name == kw::SelfLower
1725     } else {
1726         false
1727     }
1728 }
1729 
is_self_ty(slf: &hir::Ty<'_>) -> bool1730 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
1731     if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
1732         if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res {
1733             return true;
1734         }
1735     }
1736     false
1737 }
1738 
iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>>1739 pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
1740     (0..decl.inputs.len()).map(move |i| &body.params[i])
1741 }
1742 
1743 /// Checks if a given expression is a match expression expanded from the `?`
1744 /// operator or the `try` macro.
is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>1745 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
1746     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1747         if_chain! {
1748             if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
1749             if ddpos.as_opt_usize().is_none();
1750             if is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk);
1751             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
1752             if path_to_local_id(arm.body, hir_id);
1753             then {
1754                 return true;
1755             }
1756         }
1757         false
1758     }
1759 
1760     fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1761         if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
1762             is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultErr)
1763         } else {
1764             false
1765         }
1766     }
1767 
1768     if let ExprKind::Match(_, arms, ref source) = expr.kind {
1769         // desugared from a `?` operator
1770         if *source == MatchSource::TryDesugar {
1771             return Some(expr);
1772         }
1773 
1774         if_chain! {
1775             if arms.len() == 2;
1776             if arms[0].guard.is_none();
1777             if arms[1].guard.is_none();
1778             if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
1779             then {
1780                 return Some(expr);
1781             }
1782         }
1783     }
1784 
1785     None
1786 }
1787 
1788 /// Returns `true` if the lint is allowed in the current context. This is useful for
1789 /// skipping long running code when it's unnecessary
1790 ///
1791 /// This function should check the lint level for the same node, that the lint will
1792 /// be emitted at. If the information is buffered to be emitted at a later point, please
1793 /// make sure to use `span_lint_hir` functions to emit the lint. This ensures that
1794 /// expectations at the checked nodes will be fulfilled.
is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool1795 pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
1796     cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
1797 }
1798 
strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir>1799 pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
1800     while let PatKind::Ref(subpat, _) = pat.kind {
1801         pat = subpat;
1802     }
1803     pat
1804 }
1805 
int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u641806 pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
1807     Integer::from_int_ty(&tcx, ity).size().bits()
1808 }
1809 
1810 #[expect(clippy::cast_possible_wrap)]
1811 /// Turn a constant int byte representation into an i128
sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i1281812 pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
1813     let amt = 128 - int_bits(tcx, ity);
1814     ((u as i128) << amt) >> amt
1815 }
1816 
1817 #[expect(clippy::cast_sign_loss)]
1818 /// clip unused bytes
unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u1281819 pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
1820     let amt = 128 - int_bits(tcx, ity);
1821     ((u as u128) << amt) >> amt
1822 }
1823 
1824 /// clip unused bytes
clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u1281825 pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
1826     let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
1827     let amt = 128 - bits;
1828     (u << amt) >> amt
1829 }
1830 
has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool1831 pub fn has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool {
1832     attrs.iter().any(|attr| attr.has_name(symbol))
1833 }
1834 
has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool1835 pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
1836     has_attr(cx.tcx.hir().attrs(hir_id), sym::repr)
1837 }
1838 
any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool1839 pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
1840     let map = &tcx.hir();
1841     let mut prev_enclosing_node = None;
1842     let mut enclosing_node = node;
1843     while Some(enclosing_node) != prev_enclosing_node {
1844         if has_attr(map.attrs(enclosing_node), symbol) {
1845             return true;
1846         }
1847         prev_enclosing_node = Some(enclosing_node);
1848         enclosing_node = map.get_parent_item(enclosing_node).into();
1849     }
1850 
1851     false
1852 }
1853 
any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool1854 pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
1855     any_parent_has_attr(tcx, node, sym::automatically_derived)
1856 }
1857 
1858 /// Matches a function call with the given path and returns the arguments.
1859 ///
1860 /// Usage:
1861 ///
1862 /// ```rust,ignore
1863 /// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
1864 /// ```
1865 /// This function is deprecated. Use [`match_function_call_with_def_id`].
match_function_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, path: &[&str], ) -> Option<&'tcx [Expr<'tcx>]>1866 pub fn match_function_call<'tcx>(
1867     cx: &LateContext<'tcx>,
1868     expr: &'tcx Expr<'_>,
1869     path: &[&str],
1870 ) -> Option<&'tcx [Expr<'tcx>]> {
1871     if_chain! {
1872         if let ExprKind::Call(fun, args) = expr.kind;
1873         if let ExprKind::Path(ref qpath) = fun.kind;
1874         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
1875         if match_def_path(cx, fun_def_id, path);
1876         then {
1877             return Some(args);
1878         }
1879     };
1880     None
1881 }
1882 
match_function_call_with_def_id<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, fun_def_id: DefId, ) -> Option<&'tcx [Expr<'tcx>]>1883 pub fn match_function_call_with_def_id<'tcx>(
1884     cx: &LateContext<'tcx>,
1885     expr: &'tcx Expr<'_>,
1886     fun_def_id: DefId,
1887 ) -> Option<&'tcx [Expr<'tcx>]> {
1888     if_chain! {
1889         if let ExprKind::Call(fun, args) = expr.kind;
1890         if let ExprKind::Path(ref qpath) = fun.kind;
1891         if cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id);
1892         then {
1893             return Some(args);
1894         }
1895     };
1896     None
1897 }
1898 
1899 /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
1900 /// any.
1901 ///
1902 /// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items.
match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize>1903 pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
1904     let search_path = cx.get_def_path(did);
1905     paths
1906         .iter()
1907         .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
1908 }
1909 
1910 /// Checks if the given `DefId` matches the path.
match_def_path(cx: &LateContext<'_>, did: DefId, syms: &[&str]) -> bool1911 pub fn match_def_path(cx: &LateContext<'_>, did: DefId, syms: &[&str]) -> bool {
1912     // We should probably move to Symbols in Clippy as well rather than interning every time.
1913     let path = cx.get_def_path(did);
1914     syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
1915 }
1916 
1917 /// Checks if the given `DefId` matches the `libc` item.
match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool1918 pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
1919     let path = cx.get_def_path(did);
1920     // libc is meant to be used as a flat list of names, but they're all actually defined in different
1921     // modules based on the target platform. Ignore everything but crate name and the item name.
1922     path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
1923 }
1924 
1925 /// Returns the list of condition expressions and the list of blocks in a
1926 /// sequence of `if/else`.
1927 /// E.g., this returns `([a, b], [c, d, e])` for the expression
1928 /// `if a { c } else if b { d } else { e }`.
if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>)1929 pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {
1930     let mut conds = Vec::new();
1931     let mut blocks: Vec<&Block<'_>> = Vec::new();
1932 
1933     while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {
1934         conds.push(cond);
1935         if let ExprKind::Block(block, _) = then.kind {
1936             blocks.push(block);
1937         } else {
1938             panic!("ExprKind::If node is not an ExprKind::Block");
1939         }
1940 
1941         if let Some(else_expr) = r#else {
1942             expr = else_expr;
1943         } else {
1944             break;
1945         }
1946     }
1947 
1948     // final `else {..}`
1949     if !blocks.is_empty() {
1950         if let ExprKind::Block(block, _) = expr.kind {
1951             blocks.push(block);
1952         }
1953     }
1954 
1955     (conds, blocks)
1956 }
1957 
1958 /// Checks if the given function kind is an async function.
is_async_fn(kind: FnKind<'_>) -> bool1959 pub fn is_async_fn(kind: FnKind<'_>) -> bool {
1960     match kind {
1961         FnKind::ItemFn(_, _, header) => header.asyncness == IsAsync::Async,
1962         FnKind::Method(_, sig) => sig.header.asyncness == IsAsync::Async,
1963         FnKind::Closure => false,
1964     }
1965 }
1966 
1967 /// Peels away all the compiler generated code surrounding the body of an async function,
get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>>1968 pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
1969     if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind {
1970         if let ExprKind::Block(
1971             Block {
1972                 stmts: [],
1973                 expr:
1974                     Some(Expr {
1975                         kind: ExprKind::DropTemps(expr),
1976                         ..
1977                     }),
1978                 ..
1979             },
1980             _,
1981         ) = tcx.hir().body(body).value.kind
1982         {
1983             return Some(expr);
1984         }
1985     };
1986     None
1987 }
1988 
1989 // check if expr is calling method or function with #[must_use] attribute
is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool1990 pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1991     let did = match expr.kind {
1992         ExprKind::Call(path, _) => if_chain! {
1993             if let ExprKind::Path(ref qpath) = path.kind;
1994             if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
1995             then {
1996                 Some(did)
1997             } else {
1998                 None
1999             }
2000         },
2001         ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
2002         _ => None,
2003     };
2004 
2005     did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
2006 }
2007 
2008 /// Checks if an expression represents the identity function
2009 /// Only examines closures and `std::convert::identity`
is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool2010 pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
2011     /// Checks if a function's body represents the identity function. Looks for bodies of the form:
2012     /// * `|x| x`
2013     /// * `|x| return x`
2014     /// * `|x| { return x }`
2015     /// * `|x| { return x; }`
2016     fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
2017         let id = if_chain! {
2018             if let [param] = func.params;
2019             if let PatKind::Binding(_, id, _, _) = param.pat.kind;
2020             then {
2021                 id
2022             } else {
2023                 return false;
2024             }
2025         };
2026 
2027         let mut expr = func.value;
2028         loop {
2029             match expr.kind {
2030                 #[rustfmt::skip]
2031                 ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
2032                 | ExprKind::Ret(Some(e)) => expr = e,
2033                 #[rustfmt::skip]
2034                 ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
2035                     if_chain! {
2036                         if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
2037                         if let ExprKind::Ret(Some(ret_val)) = e.kind;
2038                         then {
2039                             expr = ret_val;
2040                         } else {
2041                             return false;
2042                         }
2043                     }
2044                 },
2045                 _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
2046             }
2047         }
2048     }
2049 
2050     match expr.kind {
2051         ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
2052         _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
2053     }
2054 }
2055 
2056 /// Gets the node where an expression is either used, or it's type is unified with another branch.
2057 /// Returns both the node and the `HirId` of the closest child node.
get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)>2058 pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
2059     let mut child_id = expr.hir_id;
2060     let mut iter = tcx.hir().parent_iter(child_id);
2061     loop {
2062         match iter.next() {
2063             None => break None,
2064             Some((id, Node::Block(_))) => child_id = id,
2065             Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
2066             Some((_, Node::Expr(expr))) => match expr.kind {
2067                 ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
2068                 ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
2069                 ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
2070                 _ => break Some((Node::Expr(expr), child_id)),
2071             },
2072             Some((_, node)) => break Some((node, child_id)),
2073         }
2074     }
2075 }
2076 
2077 /// Checks if the result of an expression is used, or it's type is unified with another branch.
is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool2078 pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
2079     !matches!(
2080         get_expr_use_or_unification_node(tcx, expr),
2081         None | Some((
2082             Node::Stmt(Stmt {
2083                 kind: StmtKind::Expr(_)
2084                     | StmtKind::Semi(_)
2085                     | StmtKind::Local(Local {
2086                         pat: Pat {
2087                             kind: PatKind::Wild,
2088                             ..
2089                         },
2090                         ..
2091                     }),
2092                 ..
2093             }),
2094             _
2095         ))
2096     )
2097 }
2098 
2099 /// Checks if the expression is the final expression returned from a block.
is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool2100 pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
2101     matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
2102 }
2103 
std_or_core(cx: &LateContext<'_>) -> Option<&'static str>2104 pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
2105     if !is_no_std_crate(cx) {
2106         Some("std")
2107     } else if !is_no_core_crate(cx) {
2108         Some("core")
2109     } else {
2110         None
2111     }
2112 }
2113 
is_no_std_crate(cx: &LateContext<'_>) -> bool2114 pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
2115     cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
2116         if let ast::AttrKind::Normal(ref normal) = attr.kind {
2117             normal.item.path == sym::no_std
2118         } else {
2119             false
2120         }
2121     })
2122 }
2123 
is_no_core_crate(cx: &LateContext<'_>) -> bool2124 pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
2125     cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
2126         if let ast::AttrKind::Normal(ref normal) = attr.kind {
2127             normal.item.path == sym::no_core
2128         } else {
2129             false
2130         }
2131     })
2132 }
2133 
2134 /// Check if parent of a hir node is a trait implementation block.
2135 /// For example, `f` in
2136 /// ```rust
2137 /// # struct S;
2138 /// # trait Trait { fn f(); }
2139 /// impl Trait for S {
2140 ///     fn f() {}
2141 /// }
2142 /// ```
is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool2143 pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
2144     if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
2145         matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
2146     } else {
2147         false
2148     }
2149 }
2150 
2151 /// Check if it's even possible to satisfy the `where` clause for the item.
2152 ///
2153 /// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
2154 ///
2155 /// ```ignore
2156 /// fn foo() where i32: Iterator {
2157 ///     for _ in 2i32 {}
2158 /// }
2159 /// ```
fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool2160 pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
2161     use rustc_trait_selection::traits;
2162     let predicates = cx
2163         .tcx
2164         .predicates_of(did)
2165         .predicates
2166         .iter()
2167         .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
2168     traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
2169 }
2170 
2171 /// Returns the `DefId` of the callee if the given expression is a function or method call.
fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId>2172 pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
2173     match &expr.kind {
2174         ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
2175         ExprKind::Call(
2176             Expr {
2177                 kind: ExprKind::Path(qpath),
2178                 hir_id: path_hir_id,
2179                 ..
2180             },
2181             ..,
2182         ) => {
2183             // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
2184             // deref to fn pointers, dyn Fn, impl Fn - #8850
2185             if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
2186                 cx.typeck_results().qpath_res(qpath, *path_hir_id)
2187             {
2188                 Some(id)
2189             } else {
2190                 None
2191             }
2192         },
2193         _ => None,
2194     }
2195 }
2196 
2197 /// Returns `Option<String>` where String is a textual representation of the type encapsulated in
2198 /// the slice iff the given expression is a slice of primitives (as defined in the
2199 /// `is_recursively_primitive_type` function) and `None` otherwise.
is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String>2200 pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
2201     let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
2202     let expr_kind = expr_type.kind();
2203     let is_primitive = match expr_kind {
2204         rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type),
2205         rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
2206             if let rustc_ty::Slice(element_type) = inner_ty.kind() {
2207                 is_recursively_primitive_type(*element_type)
2208             } else {
2209                 unreachable!()
2210             }
2211         },
2212         _ => false,
2213     };
2214 
2215     if is_primitive {
2216         // if we have wrappers like Array, Slice or Tuple, print these
2217         // and get the type enclosed in the slice ref
2218         match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
2219             rustc_ty::Slice(..) => return Some("slice".into()),
2220             rustc_ty::Array(..) => return Some("array".into()),
2221             rustc_ty::Tuple(..) => return Some("tuple".into()),
2222             _ => {
2223                 // is_recursively_primitive_type() should have taken care
2224                 // of the rest and we can rely on the type that is found
2225                 let refs_peeled = expr_type.peel_refs();
2226                 return Some(refs_peeled.walk().last().unwrap().to_string());
2227             },
2228         }
2229     }
2230     None
2231 }
2232 
2233 /// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
2234 /// and `a` is before `b` in `exprs` for all `a` and `b` in
2235 /// `exprs`
2236 ///
2237 /// Given functions `eq` and `hash` such that `eq(a, b) == true`
2238 /// implies `hash(a) == hash(b)`
search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)> where Hash: Fn(&T) -> u64, Eq: Fn(&T, &T) -> bool,2239 pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
2240 where
2241     Hash: Fn(&T) -> u64,
2242     Eq: Fn(&T, &T) -> bool,
2243 {
2244     match exprs {
2245         [a, b] if eq(a, b) => return vec![(a, b)],
2246         _ if exprs.len() <= 2 => return vec![],
2247         _ => {},
2248     }
2249 
2250     let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
2251 
2252     let mut map: UnhashMap<u64, Vec<&_>> =
2253         UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
2254 
2255     for expr in exprs {
2256         match map.entry(hash(expr)) {
2257             Entry::Occupied(mut o) => {
2258                 for o in o.get() {
2259                     if eq(o, expr) {
2260                         match_expr_list.push((o, expr));
2261                     }
2262                 }
2263                 o.get_mut().push(expr);
2264             },
2265             Entry::Vacant(v) => {
2266                 v.insert(vec![expr]);
2267             },
2268         }
2269     }
2270 
2271     match_expr_list
2272 }
2273 
2274 /// Peels off all references on the pattern. Returns the underlying pattern and the number of
2275 /// references removed.
peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize)2276 pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
2277     fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
2278         if let PatKind::Ref(pat, _) = pat.kind {
2279             peel(pat, count + 1)
2280         } else {
2281             (pat, count)
2282         }
2283     }
2284     peel(pat, 0)
2285 }
2286 
2287 /// Peels of expressions while the given closure returns `Some`.
peel_hir_expr_while<'tcx>( mut expr: &'tcx Expr<'tcx>, mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>, ) -> &'tcx Expr<'tcx>2288 pub fn peel_hir_expr_while<'tcx>(
2289     mut expr: &'tcx Expr<'tcx>,
2290     mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
2291 ) -> &'tcx Expr<'tcx> {
2292     while let Some(e) = f(expr) {
2293         expr = e;
2294     }
2295     expr
2296 }
2297 
2298 /// Peels off up to the given number of references on the expression. Returns the underlying
2299 /// expression and the number of references removed.
peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize)2300 pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
2301     let mut remaining = count;
2302     let e = peel_hir_expr_while(expr, |e| match e.kind {
2303         ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
2304             remaining -= 1;
2305             Some(e)
2306         },
2307         _ => None,
2308     });
2309     (e, count - remaining)
2310 }
2311 
2312 /// Peels off all unary operators of an expression. Returns the underlying expression and the number
2313 /// of operators removed.
peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize)2314 pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2315     let mut count: usize = 0;
2316     let mut curr_expr = expr;
2317     while let ExprKind::Unary(_, local_expr) = curr_expr.kind {
2318         count = count.wrapping_add(1);
2319         curr_expr = local_expr;
2320     }
2321     (curr_expr, count)
2322 }
2323 
2324 /// Peels off all references on the expression. Returns the underlying expression and the number of
2325 /// references removed.
peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize)2326 pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
2327     let mut count = 0;
2328     let e = peel_hir_expr_while(expr, |e| match e.kind {
2329         ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
2330             count += 1;
2331             Some(e)
2332         },
2333         _ => None,
2334     });
2335     (e, count)
2336 }
2337 
2338 /// Peels off all references on the type. Returns the underlying type and the number of references
2339 /// removed.
peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize)2340 pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) {
2341     let mut count = 0;
2342     loop {
2343         match &ty.kind {
2344             TyKind::Ref(_, ref_ty) => {
2345                 ty = ref_ty.ty;
2346                 count += 1;
2347             },
2348             _ => break (ty, count),
2349         }
2350     }
2351 }
2352 
2353 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
2354 /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir>2355 pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
2356     loop {
2357         match expr.kind {
2358             ExprKind::AddrOf(_, _, e) => expr = e,
2359             ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
2360             _ => break,
2361         }
2362     }
2363     expr
2364 }
2365 
is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool2366 pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
2367     if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
2368         if let Res::Def(_, def_id) = path.res {
2369             return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
2370         }
2371     }
2372     false
2373 }
2374 
2375 static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = OnceLock::new();
2376 
with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool2377 fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
2378     let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
2379     let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
2380     let value = map.entry(module);
2381     match value {
2382         Entry::Occupied(entry) => f(entry.get()),
2383         Entry::Vacant(entry) => {
2384             let mut names = Vec::new();
2385             for id in tcx.hir().module_items(module) {
2386                 if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
2387                     && let item = tcx.hir().item(id)
2388                     && let ItemKind::Const(ty, _body) = item.kind {
2389                     if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
2390                         // We could also check for the type name `test::TestDescAndFn`
2391                         if let Res::Def(DefKind::Struct, _) = path.res {
2392                             let has_test_marker = tcx
2393                                 .hir()
2394                                 .attrs(item.hir_id())
2395                                 .iter()
2396                                 .any(|a| a.has_name(sym::rustc_test_marker));
2397                             if has_test_marker {
2398                                 names.push(item.ident.name);
2399                             }
2400                         }
2401                     }
2402                 }
2403             }
2404             names.sort_unstable();
2405             f(entry.insert(names))
2406         },
2407     }
2408 }
2409 
2410 /// Checks if the function containing the given `HirId` is a `#[test]` function
2411 ///
2412 /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool2413 pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
2414     with_test_item_names(tcx, tcx.parent_module(id), |names| {
2415         tcx.hir()
2416             .parent_iter(id)
2417             // Since you can nest functions we need to collect all until we leave
2418             // function scope
2419             .any(|(_id, node)| {
2420                 if let Node::Item(item) = node {
2421                     if let ItemKind::Fn(_, _, _) = item.kind {
2422                         // Note that we have sorted the item names in the visitor,
2423                         // so the binary_search gets the same as `contains`, but faster.
2424                         return names.binary_search(&item.ident.name).is_ok();
2425                     }
2426                 }
2427                 false
2428             })
2429     })
2430 }
2431 
2432 /// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied
2433 ///
2434 /// Note: Add `//@compile-flags: --test` to UI tests with a `#[cfg(test)]` function
is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool2435 pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
2436     fn is_cfg_test(attr: &Attribute) -> bool {
2437         if attr.has_name(sym::cfg)
2438             && let Some(items) = attr.meta_item_list()
2439             && let [item] = &*items
2440             && item.has_name(sym::test)
2441         {
2442             true
2443         } else {
2444             false
2445         }
2446     }
2447     tcx.hir()
2448         .parent_iter(id)
2449         .flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id))
2450         .any(is_cfg_test)
2451 }
2452 
2453 /// Checks whether item either has `test` attribute applied, or
2454 /// is a module with `test` in its name.
2455 ///
2456 /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool2457 pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
2458     is_in_test_function(tcx, item.hir_id())
2459         || matches!(item.kind, ItemKind::Mod(..))
2460             && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
2461 }
2462 
2463 /// Walks the HIR tree from the given expression, up to the node where the value produced by the
2464 /// expression is consumed. Calls the function for every node encountered this way until it returns
2465 /// `Some`.
2466 ///
2467 /// This allows walking through `if`, `match`, `break`, block expressions to find where the value
2468 /// produced by the expression is consumed.
walk_to_expr_usage<'tcx, T>( cx: &LateContext<'tcx>, e: &Expr<'tcx>, mut f: impl FnMut(Node<'tcx>, HirId) -> Option<T>, ) -> Option<T>2469 pub fn walk_to_expr_usage<'tcx, T>(
2470     cx: &LateContext<'tcx>,
2471     e: &Expr<'tcx>,
2472     mut f: impl FnMut(Node<'tcx>, HirId) -> Option<T>,
2473 ) -> Option<T> {
2474     let map = cx.tcx.hir();
2475     let mut iter = map.parent_iter(e.hir_id);
2476     let mut child_id = e.hir_id;
2477 
2478     while let Some((parent_id, parent)) = iter.next() {
2479         if let Some(x) = f(parent, child_id) {
2480             return Some(x);
2481         }
2482         let parent = match parent {
2483             Node::Expr(e) => e,
2484             Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => {
2485                 child_id = parent_id;
2486                 continue;
2487             },
2488             Node::Arm(a) if a.body.hir_id == child_id => {
2489                 child_id = parent_id;
2490                 continue;
2491             },
2492             _ => return None,
2493         };
2494         match parent.kind {
2495             ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id,
2496             ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => {
2497                 child_id = id;
2498                 iter = map.parent_iter(id);
2499             },
2500             ExprKind::Block(..) => child_id = parent_id,
2501             _ => return None,
2502         }
2503     }
2504     None
2505 }
2506 
2507 /// Tokenizes the input while keeping the text associated with each token.
tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)>2508 pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
2509     let mut pos = 0;
2510     tokenize(s).map(move |t| {
2511         let end = pos + t.len;
2512         let range = pos as usize..end as usize;
2513         pos = end;
2514         (t.kind, s.get(range).unwrap_or_default())
2515     })
2516 }
2517 
2518 /// Checks whether a given span has any comment token
2519 /// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
span_contains_comment(sm: &SourceMap, span: Span) -> bool2520 pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
2521     let Ok(snippet) = sm.span_to_snippet(span) else { return false };
2522     return tokenize(&snippet).any(|token| {
2523         matches!(
2524             token.kind,
2525             TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
2526         )
2527     });
2528 }
2529 
2530 /// Return all the comments a given span contains
2531 /// Comments are returned wrapped with their relevant delimiters
span_extract_comment(sm: &SourceMap, span: Span) -> String2532 pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
2533     let snippet = sm.span_to_snippet(span).unwrap_or_default();
2534     let res = tokenize_with_text(&snippet)
2535         .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
2536         .map(|(_, s)| s)
2537         .join("\n");
2538     res
2539 }
2540 
span_find_starting_semi(sm: &SourceMap, span: Span) -> Span2541 pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
2542     sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
2543 }
2544 
2545 macro_rules! op_utils {
2546     ($($name:ident $assign:ident)*) => {
2547         /// Binary operation traits like `LangItem::Add`
2548         pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
2549 
2550         /// Operator-Assign traits like `LangItem::AddAssign`
2551         pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
2552 
2553         /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
2554         pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
2555             match kind {
2556                 $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
2557                 _ => None,
2558             }
2559         }
2560     };
2561 }
2562 
2563 op_utils! {
2564     Add    AddAssign
2565     Sub    SubAssign
2566     Mul    MulAssign
2567     Div    DivAssign
2568     Rem    RemAssign
2569     BitXor BitXorAssign
2570     BitAnd BitAndAssign
2571     BitOr  BitOrAssign
2572     Shl    ShlAssign
2573     Shr    ShrAssign
2574 }
2575