]> git.lizzy.rs Git - rust.git/blob - clippy_utils/src/lib.rs
00db52a9457d85d50b30fb15da254764a55aa835
[rust.git] / clippy_utils / src / lib.rs
1 #![feature(box_patterns)]
2 #![feature(in_band_lifetimes)]
3 #![feature(iter_zip)]
4 #![feature(rustc_private)]
5 #![recursion_limit = "512"]
6 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
7 #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
8 // warn on the same lints as `clippy_lints`
9 #![warn(trivial_casts, trivial_numeric_casts)]
10 // warn on lints, that are included in `rust-lang/rust`s bootstrap
11 #![warn(rust_2018_idioms, unused_lifetimes)]
12 // warn on rustc internal lints
13 #![warn(rustc::internal)]
14
15 // FIXME: switch to something more ergonomic here, once available.
16 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
17 extern crate rustc_ast;
18 extern crate rustc_ast_pretty;
19 extern crate rustc_attr;
20 extern crate rustc_data_structures;
21 extern crate rustc_errors;
22 extern crate rustc_hir;
23 extern crate rustc_infer;
24 extern crate rustc_lexer;
25 extern crate rustc_lint;
26 extern crate rustc_middle;
27 extern crate rustc_mir;
28 extern crate rustc_session;
29 extern crate rustc_span;
30 extern crate rustc_target;
31 extern crate rustc_trait_selection;
32 extern crate rustc_typeck;
33
34 #[macro_use]
35 pub mod sym_helper;
36
37 #[allow(clippy::module_name_repetitions)]
38 pub mod ast_utils;
39 pub mod attrs;
40 pub mod camel_case;
41 pub mod comparisons;
42 pub mod consts;
43 pub mod diagnostics;
44 pub mod eager_or_lazy;
45 pub mod higher;
46 mod hir_utils;
47 pub mod msrvs;
48 pub mod numeric_literal;
49 pub mod paths;
50 pub mod ptr;
51 pub mod qualify_min_const_fn;
52 pub mod source;
53 pub mod sugg;
54 pub mod ty;
55 pub mod usage;
56 pub mod visitors;
57
58 pub use self::attrs::*;
59 pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, SpanlessHash};
60
61 use std::collections::hash_map::Entry;
62 use std::hash::BuildHasherDefault;
63
64 use if_chain::if_chain;
65 use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
66 use rustc_data_structures::unhash::UnhashMap;
67 use rustc_hir as hir;
68 use rustc_hir::def::{DefKind, Res};
69 use rustc_hir::def_id::DefId;
70 use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
71 use rustc_hir::LangItem::{ResultErr, ResultOk};
72 use rustc_hir::{
73     def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
74     ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Node, Param, Pat, PatKind, Path,
75     PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
76 };
77 use rustc_lint::{LateContext, Level, Lint, LintContext};
78 use rustc_middle::hir::exports::Export;
79 use rustc_middle::hir::map::Map;
80 use rustc_middle::ty as rustc_ty;
81 use rustc_middle::ty::{layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable};
82 use rustc_semver::RustcVersion;
83 use rustc_session::Session;
84 use rustc_span::hygiene::{ExpnKind, MacroKind};
85 use rustc_span::source_map::original_sp;
86 use rustc_span::sym;
87 use rustc_span::symbol::{kw, Symbol};
88 use rustc_span::{Span, DUMMY_SP};
89 use rustc_target::abi::Integer;
90
91 use crate::consts::{constant, Constant};
92 use crate::ty::{can_partially_move_ty, is_recursively_primitive_type};
93
94 pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
95     if let Ok(version) = RustcVersion::parse(msrv) {
96         return Some(version);
97     } else if let Some(sess) = sess {
98         if let Some(span) = span {
99             sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv));
100         }
101     }
102     None
103 }
104
105 pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
106     msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
107 }
108
109 #[macro_export]
110 macro_rules! extract_msrv_attr {
111     (LateContext) => {
112         extract_msrv_attr!(@LateContext, ());
113     };
114     (EarlyContext) => {
115         extract_msrv_attr!(@EarlyContext);
116     };
117     (@$context:ident$(, $call:tt)?) => {
118         fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
119             use $crate::get_unique_inner_attr;
120             match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
121                 Some(msrv_attr) => {
122                     if let Some(msrv) = msrv_attr.value_str() {
123                         self.msrv = $crate::parse_msrv(
124                             &msrv.to_string(),
125                             Some(cx.sess$($call)?),
126                             Some(msrv_attr.span),
127                         );
128                     } else {
129                         cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
130                     }
131                 },
132                 _ => (),
133             }
134         }
135     };
136 }
137
138 /// Returns `true` if the two spans come from differing expansions (i.e., one is
139 /// from a macro and one isn't).
140 #[must_use]
141 pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
142     rhs.ctxt() != lhs.ctxt()
143 }
144
145 /// If the given expression is a local binding, find the initializer expression.
146 /// If that initializer expression is another local binding, find its initializer again.
147 /// This process repeats as long as possible (but usually no more than once). Initializer
148 /// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
149 /// instead.
150 ///
151 /// Examples:
152 /// ```ignore
153 /// let abc = 1;
154 /// //        ^ output
155 /// let def = abc;
156 /// dbg!(def)
157 /// //   ^^^ input
158 ///
159 /// // or...
160 /// let abc = 1;
161 /// let def = abc + 2;
162 /// //        ^^^^^^^ output
163 /// dbg!(def)
164 /// //   ^^^ input
165 /// ```
166 pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
167     while let Some(init) = path_to_local(expr)
168         .and_then(|id| find_binding_init(cx, id))
169         .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
170     {
171         expr = init;
172     }
173     expr
174 }
175
176 /// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
177 /// By only considering immutable bindings, we guarantee that the returned expression represents the
178 /// value of the binding wherever it is referenced.
179 ///
180 /// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
181 /// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
182 /// canonical binding `HirId`.
183 pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
184     let hir = cx.tcx.hir();
185     if_chain! {
186         if let Some(Node::Binding(pat)) = hir.find(hir_id);
187         if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
188         let parent = hir.get_parent_node(hir_id);
189         if let Some(Node::Local(local)) = hir.find(parent);
190         then {
191             return local.init;
192         }
193     }
194     None
195 }
196
197 /// Returns `true` if the given `NodeId` is inside a constant context
198 ///
199 /// # Example
200 ///
201 /// ```rust,ignore
202 /// if in_constant(cx, expr.hir_id) {
203 ///     // Do something
204 /// }
205 /// ```
206 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
207     let parent_id = cx.tcx.hir().get_parent_item(id);
208     match cx.tcx.hir().get(parent_id) {
209         Node::Item(&Item {
210             kind: ItemKind::Const(..) | ItemKind::Static(..),
211             ..
212         })
213         | Node::TraitItem(&TraitItem {
214             kind: TraitItemKind::Const(..),
215             ..
216         })
217         | Node::ImplItem(&ImplItem {
218             kind: ImplItemKind::Const(..),
219             ..
220         })
221         | Node::AnonConst(_) => true,
222         Node::Item(&Item {
223             kind: ItemKind::Fn(ref sig, ..),
224             ..
225         })
226         | Node::ImplItem(&ImplItem {
227             kind: ImplItemKind::Fn(ref sig, _),
228             ..
229         }) => sig.header.constness == Constness::Const,
230         _ => false,
231     }
232 }
233
234 /// Checks if a `QPath` resolves to a constructor of a `LangItem`.
235 /// For example, use this to check whether a function call or a pattern is `Some(..)`.
236 pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool {
237     if let QPath::Resolved(_, path) = qpath {
238         if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
239             if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
240                 return cx.tcx.parent(ctor_id) == Some(item_id);
241             }
242         }
243     }
244     false
245 }
246
247 /// Returns `true` if this `span` was expanded by any macro.
248 #[must_use]
249 pub fn in_macro(span: Span) -> bool {
250     if span.from_expansion() {
251         !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
252     } else {
253         false
254     }
255 }
256
257 /// Checks if given pattern is a wildcard (`_`)
258 pub fn is_wild(pat: &Pat<'_>) -> bool {
259     matches!(pat.kind, PatKind::Wild)
260 }
261
262 /// Checks if the first type parameter is a lang item.
263 pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> {
264     let ty = get_qpath_generic_tys(qpath).next()?;
265
266     if let TyKind::Path(qpath) = &ty.kind {
267         cx.qpath_res(qpath, ty.hir_id)
268             .opt_def_id()
269             .map_or(false, |id| {
270                 cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id)
271             })
272             .then(|| ty)
273     } else {
274         None
275     }
276 }
277
278 /// Checks if the first type parameter is a diagnostic item.
279 pub fn is_ty_param_diagnostic_item(
280     cx: &LateContext<'_>,
281     qpath: &QPath<'tcx>,
282     item: Symbol,
283 ) -> Option<&'tcx hir::Ty<'tcx>> {
284     let ty = get_qpath_generic_tys(qpath).next()?;
285
286     if let TyKind::Path(qpath) = &ty.kind {
287         cx.qpath_res(qpath, ty.hir_id)
288             .opt_def_id()
289             .map_or(false, |id| cx.tcx.is_diagnostic_item(item, id))
290             .then(|| ty)
291     } else {
292         None
293     }
294 }
295
296 /// Checks if the method call given in `expr` belongs to the given trait.
297 /// This is a deprecated function, consider using [`is_trait_method`].
298 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
299     let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
300     let trt_id = cx.tcx.trait_of_item(def_id);
301     trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
302 }
303
304 /// Checks if a method is defined in an impl of a diagnostic item
305 pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
306     if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
307         if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
308             return cx.tcx.is_diagnostic_item(diag_item, adt.did);
309         }
310     }
311     false
312 }
313
314 /// Checks if a method is in a diagnostic item trait
315 pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
316     if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
317         return cx.tcx.is_diagnostic_item(diag_item, trait_did);
318     }
319     false
320 }
321
322 /// Checks if the method call given in `expr` belongs to the given trait.
323 pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
324     cx.typeck_results()
325         .type_dependent_def_id(expr.hir_id)
326         .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
327 }
328
329 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
330     match *path {
331         QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
332         QPath::TypeRelative(_, seg) => seg,
333         QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
334     }
335 }
336
337 pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> {
338     match path {
339         QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args),
340         QPath::TypeRelative(_, s) => s.args,
341         QPath::LangItem(..) => None,
342     }
343 }
344
345 pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
346     get_qpath_generics(path)
347         .map_or([].as_ref(), |a| a.args)
348         .iter()
349         .filter_map(|a| {
350             if let hir::GenericArg::Type(ty) = a {
351                 Some(ty)
352             } else {
353                 None
354             }
355         })
356 }
357
358 pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
359     match *path {
360         QPath::Resolved(_, path) => path.segments.get(0),
361         QPath::TypeRelative(_, seg) => Some(seg),
362         QPath::LangItem(..) => None,
363     }
364 }
365
366 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
367 /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
368 /// `QPath::Resolved.1.res.opt_def_id()`.
369 ///
370 /// Matches a `QPath` against a slice of segment string literals.
371 ///
372 /// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
373 /// `rustc_hir::QPath`.
374 ///
375 /// # Examples
376 /// ```rust,ignore
377 /// match_qpath(path, &["std", "rt", "begin_unwind"])
378 /// ```
379 pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
380     match *path {
381         QPath::Resolved(_, path) => match_path(path, segments),
382         QPath::TypeRelative(ty, segment) => match ty.kind {
383             TyKind::Path(ref inner_path) => {
384                 if let [prefix @ .., end] = segments {
385                     if match_qpath(inner_path, prefix) {
386                         return segment.ident.name.as_str() == *end;
387                     }
388                 }
389                 false
390             },
391             _ => false,
392         },
393         QPath::LangItem(..) => false,
394     }
395 }
396
397 /// If the expression is a path, resolve it. Otherwise, return `Res::Err`.
398 pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
399     if let ExprKind::Path(p) = &expr.kind {
400         cx.qpath_res(p, expr.hir_id)
401     } else {
402         Res::Err
403     }
404 }
405
406 /// Resolves the path to a `DefId` and checks if it matches the given path.
407 pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
408     cx.qpath_res(path, hir_id)
409         .opt_def_id()
410         .map_or(false, |id| match_def_path(cx, id, segments))
411 }
412
413 /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
414 pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
415     expr_path_res(cx, expr)
416         .opt_def_id()
417         .map_or(false, |id| match_def_path(cx, id, segments))
418 }
419
420 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
421 /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
422 /// `QPath::Resolved.1.res.opt_def_id()`.
423 ///
424 /// Matches a `Path` against a slice of segment string literals.
425 ///
426 /// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
427 /// `rustc_hir::Path`.
428 ///
429 /// # Examples
430 ///
431 /// ```rust,ignore
432 /// if match_path(&trait_ref.path, &paths::HASH) {
433 ///     // This is the `std::hash::Hash` trait.
434 /// }
435 ///
436 /// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
437 ///     // This is a `rustc_middle::lint::Lint`.
438 /// }
439 /// ```
440 pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
441     path.segments
442         .iter()
443         .rev()
444         .zip(segments.iter().rev())
445         .all(|(a, b)| a.ident.name.as_str() == *b)
446 }
447
448 /// If the expression is a path to a local, returns the canonical `HirId` of the local.
449 pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
450     if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
451         if let Res::Local(id) = path.res {
452             return Some(id);
453         }
454     }
455     None
456 }
457
458 /// Returns true if the expression is a path to a local with the specified `HirId`.
459 /// Use this function to see if an expression matches a function argument or a match binding.
460 pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
461     path_to_local(expr) == Some(id)
462 }
463
464 /// Gets the definition associated to a path.
465 #[allow(clippy::shadow_unrelated)] // false positive #6563
466 pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
467     macro_rules! try_res {
468         ($e:expr) => {
469             match $e {
470                 Some(e) => e,
471                 None => return Res::Err,
472             }
473         };
474     }
475     fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export<HirId>> {
476         tcx.item_children(def_id)
477             .iter()
478             .find(|item| item.ident.name.as_str() == name)
479     }
480
481     let (krate, first, path) = match *path {
482         [krate, first, ref path @ ..] => (krate, first, path),
483         _ => return Res::Err,
484     };
485     let tcx = cx.tcx;
486     let crates = tcx.crates(());
487     let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
488     let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
489     let last = path
490         .iter()
491         .copied()
492         // `get_def_path` seems to generate these empty segments for extern blocks.
493         // We can just ignore them.
494         .filter(|segment| !segment.is_empty())
495         // for each segment, find the child item
496         .try_fold(first, |item, segment| {
497             let def_id = item.res.def_id();
498             if let Some(item) = item_child_by_name(tcx, def_id, segment) {
499                 Some(item)
500             } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
501                 // it is not a child item so check inherent impl items
502                 tcx.inherent_impls(def_id)
503                     .iter()
504                     .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
505             } else {
506                 None
507             }
508         });
509     try_res!(last).res
510 }
511
512 /// Convenience function to get the `DefId` of a trait by path.
513 /// It could be a trait or trait alias.
514 pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
515     match path_to_res(cx, path) {
516         Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
517         _ => None,
518     }
519 }
520
521 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
522 ///
523 /// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
524 ///
525 /// ```rust
526 /// struct Point(isize, isize);
527 ///
528 /// impl std::ops::Add for Point {
529 ///     type Output = Self;
530 ///
531 ///     fn add(self, other: Self) -> Self {
532 ///         Point(0, 0)
533 ///     }
534 /// }
535 /// ```
536 pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx TraitRef<'tcx>> {
537     // Get the implemented trait for the current function
538     let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
539     if_chain! {
540         if parent_impl != hir::CRATE_HIR_ID;
541         if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
542         if let hir::ItemKind::Impl(impl_) = &item.kind;
543         then { return impl_.of_trait.as_ref(); }
544     }
545     None
546 }
547
548 /// Checks if the top level expression can be moved into a closure as is.
549 pub fn can_move_expr_to_closure_no_visit(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, jump_targets: &[HirId]) -> bool {
550     match expr.kind {
551         ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
552         | ExprKind::Continue(Destination { target_id: Ok(id), .. })
553             if jump_targets.contains(&id) =>
554         {
555             true
556         },
557         ExprKind::Break(..)
558         | ExprKind::Continue(_)
559         | ExprKind::Ret(_)
560         | ExprKind::Yield(..)
561         | ExprKind::InlineAsm(_)
562         | ExprKind::LlvmInlineAsm(_) => false,
563         // Accessing a field of a local value can only be done if the type isn't
564         // partially moved.
565         ExprKind::Field(base_expr, _)
566             if matches!(
567                 base_expr.kind,
568                 ExprKind::Path(QPath::Resolved(_, Path { res: Res::Local(_), .. }))
569             ) && can_partially_move_ty(cx, cx.typeck_results().expr_ty(base_expr)) =>
570         {
571             // TODO: check if the local has been partially moved. Assume it has for now.
572             false
573         }
574         _ => true,
575     }
576 }
577
578 /// Checks if the expression can be moved into a closure as is.
579 pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
580     struct V<'cx, 'tcx> {
581         cx: &'cx LateContext<'tcx>,
582         loops: Vec<HirId>,
583         allow_closure: bool,
584     }
585     impl Visitor<'tcx> for V<'_, 'tcx> {
586         type Map = ErasedMap<'tcx>;
587         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
588             NestedVisitorMap::None
589         }
590
591         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
592             if !self.allow_closure {
593                 return;
594             }
595             if let ExprKind::Loop(b, ..) = e.kind {
596                 self.loops.push(e.hir_id);
597                 self.visit_block(b);
598                 self.loops.pop();
599             } else {
600                 self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops);
601                 walk_expr(self, e);
602             }
603         }
604     }
605
606     let mut v = V {
607         cx,
608         allow_closure: true,
609         loops: Vec::new(),
610     };
611     v.visit_expr(expr);
612     v.allow_closure
613 }
614
615 /// Returns the method names and argument list of nested method call expressions that make up
616 /// `expr`. method/span lists are sorted with the most recent call first.
617 pub fn method_calls<'tcx>(
618     expr: &'tcx Expr<'tcx>,
619     max_depth: usize,
620 ) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
621     let mut method_names = Vec::with_capacity(max_depth);
622     let mut arg_lists = Vec::with_capacity(max_depth);
623     let mut spans = Vec::with_capacity(max_depth);
624
625     let mut current = expr;
626     for _ in 0..max_depth {
627         if let ExprKind::MethodCall(path, span, args, _) = &current.kind {
628             if args.iter().any(|e| e.span.from_expansion()) {
629                 break;
630             }
631             method_names.push(path.ident.name);
632             arg_lists.push(&**args);
633             spans.push(*span);
634             current = &args[0];
635         } else {
636             break;
637         }
638     }
639
640     (method_names, arg_lists, spans)
641 }
642
643 /// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
644 ///
645 /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
646 /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
647 /// containing the `Expr`s for
648 /// `.bar()` and `.baz()`
649 pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
650     let mut current = expr;
651     let mut matched = Vec::with_capacity(methods.len());
652     for method_name in methods.iter().rev() {
653         // method chains are stored last -> first
654         if let ExprKind::MethodCall(path, _, args, _) = current.kind {
655             if path.ident.name.as_str() == *method_name {
656                 if args.iter().any(|e| e.span.from_expansion()) {
657                     return None;
658                 }
659                 matched.push(args); // build up `matched` backwards
660                 current = &args[0]; // go to parent expression
661             } else {
662                 return None;
663             }
664         } else {
665             return None;
666         }
667     }
668     // Reverse `matched` so that it is in the same order as `methods`.
669     matched.reverse();
670     Some(matched)
671 }
672
673 /// Returns `true` if the provided `def_id` is an entrypoint to a program.
674 pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
675     cx.tcx
676         .entry_fn(())
677         .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
678 }
679
680 /// Returns `true` if the expression is in the program's `#[panic_handler]`.
681 pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
682     let parent = cx.tcx.hir().get_parent_item(e.hir_id);
683     let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
684     Some(def_id) == cx.tcx.lang_items().panic_impl()
685 }
686
687 /// Gets the name of the item the expression is in, if available.
688 pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
689     let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
690     match cx.tcx.hir().find(parent_id) {
691         Some(
692             Node::Item(Item { ident, .. })
693             | Node::TraitItem(TraitItem { ident, .. })
694             | Node::ImplItem(ImplItem { ident, .. }),
695         ) => Some(ident.name),
696         _ => None,
697     }
698 }
699
700 pub struct ContainsName {
701     pub name: Symbol,
702     pub result: bool,
703 }
704
705 impl<'tcx> Visitor<'tcx> for ContainsName {
706     type Map = Map<'tcx>;
707
708     fn visit_name(&mut self, _: Span, name: Symbol) {
709         if self.name == name {
710             self.result = true;
711         }
712     }
713     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
714         NestedVisitorMap::None
715     }
716 }
717
718 /// Checks if an `Expr` contains a certain name.
719 pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
720     let mut cn = ContainsName { name, result: false };
721     cn.visit_expr(expr);
722     cn.result
723 }
724
725 /// Returns `true` if `expr` contains a return expression
726 pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
727     struct RetCallFinder {
728         found: bool,
729     }
730
731     impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
732         type Map = Map<'tcx>;
733
734         fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
735             if self.found {
736                 return;
737             }
738             if let hir::ExprKind::Ret(..) = &expr.kind {
739                 self.found = true;
740             } else {
741                 hir::intravisit::walk_expr(self, expr);
742             }
743         }
744
745         fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
746             hir::intravisit::NestedVisitorMap::None
747         }
748     }
749
750     let mut visitor = RetCallFinder { found: false };
751     visitor.visit_expr(expr);
752     visitor.found
753 }
754
755 struct FindMacroCalls<'a, 'b> {
756     names: &'a [&'b str],
757     result: Vec<Span>,
758 }
759
760 impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
761     type Map = Map<'tcx>;
762
763     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
764         if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
765             self.result.push(expr.span);
766         }
767         // and check sub-expressions
768         intravisit::walk_expr(self, expr);
769     }
770
771     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
772         NestedVisitorMap::None
773     }
774 }
775
776 /// Finds calls of the specified macros in a function body.
777 pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
778     let mut fmc = FindMacroCalls {
779         names,
780         result: Vec::new(),
781     };
782     fmc.visit_expr(&body.value);
783     fmc.result
784 }
785
786 /// Extends the span to the beginning of the spans line, incl. whitespaces.
787 ///
788 /// ```rust,ignore
789 ///        let x = ();
790 /// //             ^^
791 /// // will be converted to
792 ///        let x = ();
793 /// // ^^^^^^^^^^^^^^
794 /// ```
795 fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
796     let span = original_sp(span, DUMMY_SP);
797     let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
798     let line_no = source_map_and_line.line;
799     let line_start = source_map_and_line.sf.lines[line_no];
800     Span::new(line_start, span.hi(), span.ctxt())
801 }
802
803 /// Gets the parent node, if any.
804 pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
805     tcx.hir().parent_iter(id).next().map(|(_, node)| node)
806 }
807
808 /// Gets the parent expression, if any â€“- this is useful to constrain a lint.
809 pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
810     get_parent_expr_for_hir(cx, e.hir_id)
811 }
812
813 /// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
814 /// constraint lints
815 pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
816     match get_parent_node(cx.tcx, hir_id) {
817         Some(Node::Expr(parent)) => Some(parent),
818         _ => None,
819     }
820 }
821
822 pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
823     let map = &cx.tcx.hir();
824     let enclosing_node = map
825         .get_enclosing_scope(hir_id)
826         .and_then(|enclosing_id| map.find(enclosing_id));
827     enclosing_node.and_then(|node| match node {
828         Node::Block(block) => Some(block),
829         Node::Item(&Item {
830             kind: ItemKind::Fn(_, _, eid),
831             ..
832         })
833         | Node::ImplItem(&ImplItem {
834             kind: ImplItemKind::Fn(_, eid),
835             ..
836         }) => match cx.tcx.hir().body(eid).value.kind {
837             ExprKind::Block(block, _) => Some(block),
838             _ => None,
839         },
840         _ => None,
841     })
842 }
843
844 /// Gets the loop or closure enclosing the given expression, if any.
845 pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
846     let map = tcx.hir();
847     for (_, node) in map.parent_iter(expr.hir_id) {
848         match node {
849             Node::Expr(
850                 e
851                 @
852                 Expr {
853                     kind: ExprKind::Loop(..) | ExprKind::Closure(..),
854                     ..
855                 },
856             ) => return Some(e),
857             Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
858             _ => break,
859         }
860     }
861     None
862 }
863
864 /// Gets the parent node if it's an impl block.
865 pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
866     let map = tcx.hir();
867     match map.parent_iter(id).next() {
868         Some((
869             _,
870             Node::Item(Item {
871                 kind: ItemKind::Impl(imp),
872                 ..
873             }),
874         )) => Some(imp),
875         _ => None,
876     }
877 }
878
879 /// Checks if the given expression is the else clause of either an `if` or `if let` expression.
880 pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
881     let map = tcx.hir();
882     let mut iter = map.parent_iter(expr.hir_id);
883     match iter.next() {
884         Some((arm_id, Node::Arm(..))) => matches!(
885             iter.next(),
886             Some((
887                 _,
888                 Node::Expr(Expr {
889                     kind: ExprKind::Match(_, [_, else_arm], MatchSource::IfLetDesugar { .. }),
890                     ..
891                 })
892             ))
893             if else_arm.hir_id == arm_id
894         ),
895         Some((
896             _,
897             Node::Expr(Expr {
898                 kind: ExprKind::If(_, _, Some(else_expr)),
899                 ..
900             }),
901         )) => else_expr.hir_id == expr.hir_id,
902         _ => false,
903     }
904 }
905
906 /// Checks whether the given expression is a constant integer of the given value.
907 /// unlike `is_integer_literal`, this version does const folding
908 pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
909     if is_integer_literal(e, value) {
910         return true;
911     }
912     let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
913     if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
914         value == v
915     } else {
916         false
917     }
918 }
919
920 /// Checks whether the given expression is a constant literal of the given value.
921 pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
922     // FIXME: use constant folding
923     if let ExprKind::Lit(ref spanned) = expr.kind {
924         if let LitKind::Int(v, _) = spanned.node {
925             return v == value;
926         }
927     }
928     false
929 }
930
931 /// Returns `true` if the given `Expr` has been coerced before.
932 ///
933 /// Examples of coercions can be found in the Nomicon at
934 /// <https://doc.rust-lang.org/nomicon/coercions.html>.
935 ///
936 /// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
937 /// information on adjustments and coercions.
938 pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
939     cx.typeck_results().adjustments().get(e.hir_id).is_some()
940 }
941
942 /// Returns the pre-expansion span if is this comes from an expansion of the
943 /// macro `name`.
944 /// See also `is_direct_expn_of`.
945 #[must_use]
946 pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
947     loop {
948         if span.from_expansion() {
949             let data = span.ctxt().outer_expn_data();
950             let new_span = data.call_site;
951
952             if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
953                 if mac_name.as_str() == name {
954                     return Some(new_span);
955                 }
956             }
957
958             span = new_span;
959         } else {
960             return None;
961         }
962     }
963 }
964
965 /// Returns the pre-expansion span if the span directly comes from an expansion
966 /// of the macro `name`.
967 /// The difference with `is_expn_of` is that in
968 /// ```rust,ignore
969 /// foo!(bar!(42));
970 /// ```
971 /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
972 /// `bar!` by
973 /// `is_direct_expn_of`.
974 #[must_use]
975 pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
976     if span.from_expansion() {
977         let data = span.ctxt().outer_expn_data();
978         let new_span = data.call_site;
979
980         if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
981             if mac_name.as_str() == name {
982                 return Some(new_span);
983             }
984         }
985     }
986
987     None
988 }
989
990 /// Convenience function to get the return type of a function.
991 pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
992     let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
993     let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
994     cx.tcx.erase_late_bound_regions(ret_ty)
995 }
996
997 /// Checks if an expression is constructing a tuple-like enum variant or struct
998 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
999     if let ExprKind::Call(fun, _) = expr.kind {
1000         if let ExprKind::Path(ref qp) = fun.kind {
1001             let res = cx.qpath_res(qp, fun.hir_id);
1002             return match res {
1003                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
1004                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
1005                 _ => false,
1006             };
1007         }
1008     }
1009     false
1010 }
1011
1012 /// Returns `true` if a pattern is refutable.
1013 // TODO: should be implemented using rustc/mir_build/thir machinery
1014 pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
1015     fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
1016         matches!(
1017             cx.qpath_res(qpath, id),
1018             def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
1019         )
1020     }
1021
1022     fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
1023         i.into_iter().any(|pat| is_refutable(cx, pat))
1024     }
1025
1026     match pat.kind {
1027         PatKind::Wild => false,
1028         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
1029         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
1030         PatKind::Lit(..) | PatKind::Range(..) => true,
1031         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
1032         PatKind::Or(pats) => {
1033             // TODO: should be the honest check, that pats is exhaustive set
1034             are_refutable(cx, pats)
1035         },
1036         PatKind::Tuple(pats, _) => are_refutable(cx, pats),
1037         PatKind::Struct(ref qpath, fields, _) => {
1038             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
1039         },
1040         PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
1041         PatKind::Slice(head, middle, tail) => {
1042             match &cx.typeck_results().node_type(pat.hir_id).kind() {
1043                 rustc_ty::Slice(..) => {
1044                     // [..] is the only irrefutable slice pattern.
1045                     !head.is_empty() || middle.is_none() || !tail.is_empty()
1046                 },
1047                 rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
1048                 _ => {
1049                     // unreachable!()
1050                     true
1051                 },
1052             }
1053         },
1054     }
1055 }
1056
1057 /// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
1058 /// the function once on the given pattern.
1059 pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
1060     if let PatKind::Or(pats) = pat.kind {
1061         pats.iter().for_each(f);
1062     } else {
1063         f(pat);
1064     }
1065 }
1066
1067 /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
1068 /// implementations have.
1069 pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
1070     attrs.iter().any(|attr| attr.has_name(sym::automatically_derived))
1071 }
1072
1073 /// Remove blocks around an expression.
1074 ///
1075 /// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
1076 /// themselves.
1077 pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
1078     while let ExprKind::Block(block, ..) = expr.kind {
1079         match (block.stmts.is_empty(), block.expr.as_ref()) {
1080             (true, Some(e)) => expr = e,
1081             _ => break,
1082         }
1083     }
1084     expr
1085 }
1086
1087 pub fn is_self(slf: &Param<'_>) -> bool {
1088     if let PatKind::Binding(.., name, _) = slf.pat.kind {
1089         name.name == kw::SelfLower
1090     } else {
1091         false
1092     }
1093 }
1094
1095 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
1096     if_chain! {
1097         if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
1098         if let Res::SelfTy(..) = path.res;
1099         then {
1100             return true
1101         }
1102     }
1103     false
1104 }
1105
1106 pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
1107     (0..decl.inputs.len()).map(move |i| &body.params[i])
1108 }
1109
1110 /// Checks if a given expression is a match expression expanded from the `?`
1111 /// operator or the `try` macro.
1112 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
1113     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1114         if_chain! {
1115             if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
1116             if is_lang_ctor(cx, path, ResultOk);
1117             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
1118             if path_to_local_id(arm.body, hir_id);
1119             then {
1120                 return true;
1121             }
1122         }
1123         false
1124     }
1125
1126     fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
1127         if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
1128             is_lang_ctor(cx, path, ResultErr)
1129         } else {
1130             false
1131         }
1132     }
1133
1134     if let ExprKind::Match(_, arms, ref source) = expr.kind {
1135         // desugared from a `?` operator
1136         if let MatchSource::TryDesugar = *source {
1137             return Some(expr);
1138         }
1139
1140         if_chain! {
1141             if arms.len() == 2;
1142             if arms[0].guard.is_none();
1143             if arms[1].guard.is_none();
1144             if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) ||
1145                 (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
1146             then {
1147                 return Some(expr);
1148             }
1149         }
1150     }
1151
1152     None
1153 }
1154
1155 /// Returns `true` if the lint is allowed in the current context
1156 ///
1157 /// Useful for skipping long running code when it's unnecessary
1158 pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
1159     cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
1160 }
1161
1162 pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
1163     while let PatKind::Ref(subpat, _) = pat.kind {
1164         pat = subpat;
1165     }
1166     pat
1167 }
1168
1169 pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
1170     Integer::from_int_ty(&tcx, ity).size().bits()
1171 }
1172
1173 #[allow(clippy::cast_possible_wrap)]
1174 /// Turn a constant int byte representation into an i128
1175 pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
1176     let amt = 128 - int_bits(tcx, ity);
1177     ((u as i128) << amt) >> amt
1178 }
1179
1180 #[allow(clippy::cast_sign_loss)]
1181 /// clip unused bytes
1182 pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
1183     let amt = 128 - int_bits(tcx, ity);
1184     ((u as u128) << amt) >> amt
1185 }
1186
1187 /// clip unused bytes
1188 pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
1189     let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
1190     let amt = 128 - bits;
1191     (u << amt) >> amt
1192 }
1193
1194 pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
1195     let map = &tcx.hir();
1196     let mut prev_enclosing_node = None;
1197     let mut enclosing_node = node;
1198     while Some(enclosing_node) != prev_enclosing_node {
1199         if is_automatically_derived(map.attrs(enclosing_node)) {
1200             return true;
1201         }
1202         prev_enclosing_node = Some(enclosing_node);
1203         enclosing_node = map.get_parent_item(enclosing_node);
1204     }
1205     false
1206 }
1207
1208 /// Matches a function call with the given path and returns the arguments.
1209 ///
1210 /// Usage:
1211 ///
1212 /// ```rust,ignore
1213 /// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
1214 /// ```
1215 pub fn match_function_call<'tcx>(
1216     cx: &LateContext<'tcx>,
1217     expr: &'tcx Expr<'_>,
1218     path: &[&str],
1219 ) -> Option<&'tcx [Expr<'tcx>]> {
1220     if_chain! {
1221         if let ExprKind::Call(fun, args) = expr.kind;
1222         if let ExprKind::Path(ref qpath) = fun.kind;
1223         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
1224         if match_def_path(cx, fun_def_id, path);
1225         then {
1226             return Some(args)
1227         }
1228     };
1229     None
1230 }
1231
1232 /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
1233 /// any.
1234 pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
1235     let search_path = cx.get_def_path(did);
1236     paths
1237         .iter()
1238         .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
1239 }
1240
1241 /// Checks if the given `DefId` matches the path.
1242 pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
1243     // We should probably move to Symbols in Clippy as well rather than interning every time.
1244     let path = cx.get_def_path(did);
1245     syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
1246 }
1247
1248 pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
1249     if let ExprKind::Call(func, [arg]) = expr.kind {
1250         expr_path_res(cx, func)
1251             .opt_def_id()
1252             .map_or(false, |id| match_panic_def_id(cx, id))
1253             .then(|| arg)
1254     } else {
1255         None
1256     }
1257 }
1258
1259 pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
1260     match_any_def_paths(
1261         cx,
1262         did,
1263         &[
1264             &paths::BEGIN_PANIC,
1265             &paths::BEGIN_PANIC_FMT,
1266             &paths::PANIC_ANY,
1267             &paths::PANICKING_PANIC,
1268             &paths::PANICKING_PANIC_FMT,
1269             &paths::PANICKING_PANIC_STR,
1270         ],
1271     )
1272     .is_some()
1273 }
1274
1275 /// Returns the list of condition expressions and the list of blocks in a
1276 /// sequence of `if/else`.
1277 /// E.g., this returns `([a, b], [c, d, e])` for the expression
1278 /// `if a { c } else if b { d } else { e }`.
1279 pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {
1280     let mut conds = Vec::new();
1281     let mut blocks: Vec<&Block<'_>> = Vec::new();
1282
1283     while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind {
1284         conds.push(cond);
1285         if let ExprKind::Block(block, _) = then_expr.kind {
1286             blocks.push(block);
1287         } else {
1288             panic!("ExprKind::If node is not an ExprKind::Block");
1289         }
1290
1291         if let Some(else_expr) = *else_expr {
1292             expr = else_expr;
1293         } else {
1294             break;
1295         }
1296     }
1297
1298     // final `else {..}`
1299     if !blocks.is_empty() {
1300         if let ExprKind::Block(block, _) = expr.kind {
1301             blocks.push(block);
1302         }
1303     }
1304
1305     (conds, blocks)
1306 }
1307
1308 /// Checks if the given function kind is an async function.
1309 pub fn is_async_fn(kind: FnKind<'_>) -> bool {
1310     matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
1311 }
1312
1313 /// Peels away all the compiler generated code surrounding the body of an async function,
1314 pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
1315     if let ExprKind::Call(
1316         _,
1317         &[Expr {
1318             kind: ExprKind::Closure(_, _, body, _, _),
1319             ..
1320         }],
1321     ) = body.value.kind
1322     {
1323         if let ExprKind::Block(
1324             Block {
1325                 stmts: [],
1326                 expr:
1327                     Some(Expr {
1328                         kind: ExprKind::DropTemps(expr),
1329                         ..
1330                     }),
1331                 ..
1332             },
1333             _,
1334         ) = tcx.hir().body(body).value.kind
1335         {
1336             return Some(expr);
1337         }
1338     };
1339     None
1340 }
1341
1342 // Finds the `#[must_use]` attribute, if any
1343 pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
1344     attrs.iter().find(|a| a.has_name(sym::must_use))
1345 }
1346
1347 // check if expr is calling method or function with #[must_use] attribute
1348 pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1349     let did = match expr.kind {
1350         ExprKind::Call(path, _) => if_chain! {
1351             if let ExprKind::Path(ref qpath) = path.kind;
1352             if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
1353             then {
1354                 Some(did)
1355             } else {
1356                 None
1357             }
1358         },
1359         ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
1360         _ => None,
1361     };
1362
1363     did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
1364 }
1365
1366 /// Checks if an expression represents the identity function
1367 /// Only examines closures and `std::convert::identity`
1368 pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1369     /// Checks if a function's body represents the identity function. Looks for bodies of the form:
1370     /// * `|x| x`
1371     /// * `|x| return x`
1372     /// * `|x| { return x }`
1373     /// * `|x| { return x; }`
1374     fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
1375         let id = if_chain! {
1376             if let [param] = func.params;
1377             if let PatKind::Binding(_, id, _, _) = param.pat.kind;
1378             then {
1379                 id
1380             } else {
1381                 return false;
1382             }
1383         };
1384
1385         let mut expr = &func.value;
1386         loop {
1387             match expr.kind {
1388                 #[rustfmt::skip]
1389                 ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
1390                 | ExprKind::Ret(Some(e)) => expr = e,
1391                 #[rustfmt::skip]
1392                 ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
1393                     if_chain! {
1394                         if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
1395                         if let ExprKind::Ret(Some(ret_val)) = e.kind;
1396                         then {
1397                             expr = ret_val;
1398                         } else {
1399                             return false;
1400                         }
1401                     }
1402                 },
1403                 _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
1404             }
1405         }
1406     }
1407
1408     match expr.kind {
1409         ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
1410         ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
1411         _ => false,
1412     }
1413 }
1414
1415 /// Gets the node where an expression is either used, or it's type is unified with another branch.
1416 pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
1417     let map = tcx.hir();
1418     let mut child_id = expr.hir_id;
1419     let mut iter = map.parent_iter(child_id);
1420     loop {
1421         match iter.next() {
1422             None => break None,
1423             Some((id, Node::Block(_))) => child_id = id,
1424             Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
1425             Some((_, Node::Expr(expr))) => match expr.kind {
1426                 ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
1427                 ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
1428                 ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
1429                 _ => break Some(Node::Expr(expr)),
1430             },
1431             Some((_, node)) => break Some(node),
1432         }
1433     }
1434 }
1435
1436 /// Checks if the result of an expression is used, or it's type is unified with another branch.
1437 pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1438     !matches!(
1439         get_expr_use_or_unification_node(tcx, expr),
1440         None | Some(Node::Stmt(Stmt {
1441             kind: StmtKind::Expr(_)
1442                 | StmtKind::Semi(_)
1443                 | StmtKind::Local(Local {
1444                     pat: Pat {
1445                         kind: PatKind::Wild,
1446                         ..
1447                     },
1448                     ..
1449                 }),
1450             ..
1451         }))
1452     )
1453 }
1454
1455 /// Checks if the expression is the final expression returned from a block.
1456 pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1457     matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
1458 }
1459
1460 pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
1461     cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
1462         if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
1463             attr.path == sym::no_std
1464         } else {
1465             false
1466         }
1467     })
1468 }
1469
1470 /// Check if parent of a hir node is a trait implementation block.
1471 /// For example, `f` in
1472 /// ```rust,ignore
1473 /// impl Trait for S {
1474 ///     fn f() {}
1475 /// }
1476 /// ```
1477 pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
1478     if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
1479         matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
1480     } else {
1481         false
1482     }
1483 }
1484
1485 /// Check if it's even possible to satisfy the `where` clause for the item.
1486 ///
1487 /// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
1488 ///
1489 /// ```ignore
1490 /// fn foo() where i32: Iterator {
1491 ///     for _ in 2i32 {}
1492 /// }
1493 /// ```
1494 pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
1495     use rustc_trait_selection::traits;
1496     let predicates = cx
1497         .tcx
1498         .predicates_of(did)
1499         .predicates
1500         .iter()
1501         .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
1502     traits::impossible_predicates(
1503         cx.tcx,
1504         traits::elaborate_predicates(cx.tcx, predicates)
1505             .map(|o| o.predicate)
1506             .collect::<Vec<_>>(),
1507     )
1508 }
1509
1510 /// Returns the `DefId` of the callee if the given expression is a function or method call.
1511 pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
1512     match &expr.kind {
1513         ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
1514         ExprKind::Call(
1515             Expr {
1516                 kind: ExprKind::Path(qpath),
1517                 hir_id: path_hir_id,
1518                 ..
1519             },
1520             ..,
1521         ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
1522         _ => None,
1523     }
1524 }
1525
1526 /// Returns Option<String> where String is a textual representation of the type encapsulated in the
1527 /// slice iff the given expression is a slice of primitives (as defined in the
1528 /// `is_recursively_primitive_type` function) and None otherwise.
1529 pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
1530     let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
1531     let expr_kind = expr_type.kind();
1532     let is_primitive = match expr_kind {
1533         rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type),
1534         rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
1535             if let rustc_ty::Slice(element_type) = inner_ty.kind() {
1536                 is_recursively_primitive_type(element_type)
1537             } else {
1538                 unreachable!()
1539             }
1540         },
1541         _ => false,
1542     };
1543
1544     if is_primitive {
1545         // if we have wrappers like Array, Slice or Tuple, print these
1546         // and get the type enclosed in the slice ref
1547         match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
1548             rustc_ty::Slice(..) => return Some("slice".into()),
1549             rustc_ty::Array(..) => return Some("array".into()),
1550             rustc_ty::Tuple(..) => return Some("tuple".into()),
1551             _ => {
1552                 // is_recursively_primitive_type() should have taken care
1553                 // of the rest and we can rely on the type that is found
1554                 let refs_peeled = expr_type.peel_refs();
1555                 return Some(refs_peeled.walk().last().unwrap().to_string());
1556             },
1557         }
1558     }
1559     None
1560 }
1561
1562 /// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
1563 /// `hash` must be comformed with `eq`
1564 pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
1565 where
1566     Hash: Fn(&T) -> u64,
1567     Eq: Fn(&T, &T) -> bool,
1568 {
1569     match exprs {
1570         [a, b] if eq(a, b) => return vec![(a, b)],
1571         _ if exprs.len() <= 2 => return vec![],
1572         _ => {},
1573     }
1574
1575     let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
1576
1577     let mut map: UnhashMap<u64, Vec<&_>> =
1578         UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
1579
1580     for expr in exprs {
1581         match map.entry(hash(expr)) {
1582             Entry::Occupied(mut o) => {
1583                 for o in o.get() {
1584                     if eq(o, expr) {
1585                         match_expr_list.push((o, expr));
1586                     }
1587                 }
1588                 o.get_mut().push(expr);
1589             },
1590             Entry::Vacant(v) => {
1591                 v.insert(vec![expr]);
1592             },
1593         }
1594     }
1595
1596     match_expr_list
1597 }
1598
1599 /// Peels off all references on the pattern. Returns the underlying pattern and the number of
1600 /// references removed.
1601 pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
1602     fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
1603         if let PatKind::Ref(pat, _) = pat.kind {
1604             peel(pat, count + 1)
1605         } else {
1606             (pat, count)
1607         }
1608     }
1609     peel(pat, 0)
1610 }
1611
1612 /// Peels of expressions while the given closure returns `Some`.
1613 pub fn peel_hir_expr_while<'tcx>(
1614     mut expr: &'tcx Expr<'tcx>,
1615     mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
1616 ) -> &'tcx Expr<'tcx> {
1617     while let Some(e) = f(expr) {
1618         expr = e;
1619     }
1620     expr
1621 }
1622
1623 /// Peels off up to the given number of references on the expression. Returns the underlying
1624 /// expression and the number of references removed.
1625 pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
1626     let mut remaining = count;
1627     let e = peel_hir_expr_while(expr, |e| match e.kind {
1628         ExprKind::AddrOf(BorrowKind::Ref, _, e) if remaining != 0 => {
1629             remaining -= 1;
1630             Some(e)
1631         },
1632         _ => None,
1633     });
1634     (e, count - remaining)
1635 }
1636
1637 /// Peels off all references on the expression. Returns the underlying expression and the number of
1638 /// references removed.
1639 pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
1640     let mut count = 0;
1641     let e = peel_hir_expr_while(expr, |e| match e.kind {
1642         ExprKind::AddrOf(BorrowKind::Ref, _, e) => {
1643             count += 1;
1644             Some(e)
1645         },
1646         _ => None,
1647     });
1648     (e, count)
1649 }
1650
1651 /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
1652 /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
1653 pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
1654     loop {
1655         match expr.kind {
1656             ExprKind::AddrOf(_, _, e) => expr = e,
1657             ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
1658             _ => break,
1659         }
1660     }
1661     expr
1662 }
1663
1664 #[macro_export]
1665 macro_rules! unwrap_cargo_metadata {
1666     ($cx: ident, $lint: ident, $deps: expr) => {{
1667         let mut command = cargo_metadata::MetadataCommand::new();
1668         if !$deps {
1669             command.no_deps();
1670         }
1671
1672         match command.exec() {
1673             Ok(metadata) => metadata,
1674             Err(err) => {
1675                 span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err));
1676                 return;
1677             },
1678         }
1679     }};
1680 }
1681
1682 pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
1683     if_chain! {
1684         if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
1685         if let Res::Def(_, def_id) = path.res;
1686         then {
1687             cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
1688         } else {
1689             false
1690         }
1691     }
1692 }
1693
1694 /// Checks whether item either has `test` attribute applied, or
1695 /// is a module with `test` in its name.
1696 pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
1697     if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) {
1698         if tcx.has_attr(def_id.to_def_id(), sym::test) {
1699             return true;
1700         }
1701     }
1702
1703     matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
1704 }
1705
1706 macro_rules! op_utils {
1707     ($($name:ident $assign:ident)*) => {
1708         /// Binary operation traits like `LangItem::Add`
1709         pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
1710
1711         /// Operator-Assign traits like `LangItem::AddAssign`
1712         pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
1713
1714         /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
1715         pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
1716             match kind {
1717                 $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
1718                 _ => None,
1719             }
1720         }
1721     };
1722 }
1723
1724 op_utils! {
1725     Add    AddAssign
1726     Sub    SubAssign
1727     Mul    MulAssign
1728     Div    DivAssign
1729     Rem    RemAssign
1730     BitXor BitXorAssign
1731     BitAnd BitAndAssign
1732     BitOr  BitOrAssign
1733     Shl    ShlAssign
1734     Shr    ShrAssign
1735 }