]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/types.rs
Auto merge of #6807 - anall:feature/use_new_diagnostics, r=Manishearth
[rust.git] / clippy_lints / src / types.rs
1 #![allow(rustc::default_hash_types)]
2
3 use std::borrow::Cow;
4 use std::cmp::Ordering;
5 use std::collections::BTreeMap;
6
7 use if_chain::if_chain;
8 use rustc_ast::{LitFloatType, LitIntType, LitKind};
9 use rustc_errors::{Applicability, DiagnosticBuilder};
10 use rustc_hir as hir;
11 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
12 use rustc_hir::{
13     BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId,
14     ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node,
15     QPath, Stmt, StmtKind, SyntheticTyParamKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
16 };
17 use rustc_lint::{LateContext, LateLintPass, LintContext};
18 use rustc_middle::hir::map::Map;
19 use rustc_middle::lint::in_external_macro;
20 use rustc_middle::ty::TypeFoldable;
21 use rustc_middle::ty::{self, FloatTy, InferTy, IntTy, Ty, TyCtxt, TyS, TypeAndMut, TypeckResults, UintTy};
22 use rustc_semver::RustcVersion;
23 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
24 use rustc_span::hygiene::{ExpnKind, MacroKind};
25 use rustc_span::source_map::Span;
26 use rustc_span::symbol::sym;
27 use rustc_target::abi::LayoutOf;
28 use rustc_target::spec::abi::Abi;
29 use rustc_typeck::hir_ty_to_ty;
30
31 use crate::consts::{constant, Constant};
32 use crate::utils::paths;
33 use crate::utils::sugg::Sugg;
34 use crate::utils::{
35     clip, comparisons, differing_macro_contexts, get_qpath_generic_tys, higher, in_constant, indent_of, int_bits,
36     is_hir_ty_cfg_dependant, is_ty_param_diagnostic_item, is_ty_param_lang_item, is_type_diagnostic_item,
37     last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args, multispan_sugg,
38     numeric_literal::NumericLiteral, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability,
39     snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
40 };
41
42 declare_clippy_lint! {
43     /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
44     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
45     ///
46     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
47     /// the heap. So if you `Box` it, you just add another level of indirection
48     /// without any benefit whatsoever.
49     ///
50     /// **Known problems:** None.
51     ///
52     /// **Example:**
53     /// ```rust,ignore
54     /// struct X {
55     ///     values: Box<Vec<Foo>>,
56     /// }
57     /// ```
58     ///
59     /// Better:
60     ///
61     /// ```rust,ignore
62     /// struct X {
63     ///     values: Vec<Foo>,
64     /// }
65     /// ```
66     pub BOX_VEC,
67     perf,
68     "usage of `Box<Vec<T>>`, vector elements are already on the heap"
69 }
70
71 declare_clippy_lint! {
72     /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
73     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
74     ///
75     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
76     /// the heap. So if you `Box` its contents, you just add another level of indirection.
77     ///
78     /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530),
79     /// 1st comment).
80     ///
81     /// **Example:**
82     /// ```rust
83     /// struct X {
84     ///     values: Vec<Box<i32>>,
85     /// }
86     /// ```
87     ///
88     /// Better:
89     ///
90     /// ```rust
91     /// struct X {
92     ///     values: Vec<i32>,
93     /// }
94     /// ```
95     pub VEC_BOX,
96     complexity,
97     "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
98 }
99
100 declare_clippy_lint! {
101     /// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
102     /// definitions
103     ///
104     /// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
105     /// represents an optional optional value which is logically the same thing as an optional
106     /// value but has an unneeded extra level of wrapping.
107     ///
108     /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
109     /// consider a custom `enum` instead, with clear names for each case.
110     ///
111     /// **Known problems:** None.
112     ///
113     /// **Example**
114     /// ```rust
115     /// fn get_data() -> Option<Option<u32>> {
116     ///     None
117     /// }
118     /// ```
119     ///
120     /// Better:
121     ///
122     /// ```rust
123     /// pub enum Contents {
124     ///     Data(Vec<u8>), // Was Some(Some(Vec<u8>))
125     ///     NotYetFetched, // Was Some(None)
126     ///     None,          // Was None
127     /// }
128     ///
129     /// fn get_data() -> Contents {
130     ///     Contents::None
131     /// }
132     /// ```
133     pub OPTION_OPTION,
134     pedantic,
135     "usage of `Option<Option<T>>`"
136 }
137
138 declare_clippy_lint! {
139     /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
140     /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
141     ///
142     /// **Why is this bad?** Gankro says:
143     ///
144     /// > The TL;DR of `LinkedList` is that it's built on a massive amount of
145     /// pointers and indirection.
146     /// > It wastes memory, it has terrible cache locality, and is all-around slow.
147     /// `RingBuf`, while
148     /// > "only" amortized for push/pop, should be faster in the general case for
149     /// almost every possible
150     /// > workload, and isn't even amortized at all if you can predict the capacity
151     /// you need.
152     /// >
153     /// > `LinkedList`s are only really good if you're doing a lot of merging or
154     /// splitting of lists.
155     /// > This is because they can just mangle some pointers instead of actually
156     /// copying the data. Even
157     /// > if you're doing a lot of insertion in the middle of the list, `RingBuf`
158     /// can still be better
159     /// > because of how expensive it is to seek to the middle of a `LinkedList`.
160     ///
161     /// **Known problems:** False positives – the instances where using a
162     /// `LinkedList` makes sense are few and far between, but they can still happen.
163     ///
164     /// **Example:**
165     /// ```rust
166     /// # use std::collections::LinkedList;
167     /// let x: LinkedList<usize> = LinkedList::new();
168     /// ```
169     pub LINKEDLIST,
170     pedantic,
171     "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`"
172 }
173
174 declare_clippy_lint! {
175     /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
176     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
177     ///
178     /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
179     /// general.
180     ///
181     /// **Known problems:** None.
182     ///
183     /// **Example:**
184     /// ```rust,ignore
185     /// fn foo(bar: &Box<T>) { ... }
186     /// ```
187     ///
188     /// Better:
189     ///
190     /// ```rust,ignore
191     /// fn foo(bar: &T) { ... }
192     /// ```
193     pub BORROWED_BOX,
194     complexity,
195     "a borrow of a boxed type"
196 }
197
198 declare_clippy_lint! {
199     /// **What it does:** Checks for use of redundant allocations anywhere in the code.
200     ///
201     /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
202     /// add an unnecessary level of indirection.
203     ///
204     /// **Known problems:** None.
205     ///
206     /// **Example:**
207     /// ```rust
208     /// # use std::rc::Rc;
209     /// fn foo(bar: Rc<&usize>) {}
210     /// ```
211     ///
212     /// Better:
213     ///
214     /// ```rust
215     /// fn foo(bar: &usize) {}
216     /// ```
217     pub REDUNDANT_ALLOCATION,
218     perf,
219     "redundant allocation"
220 }
221
222 declare_clippy_lint! {
223     /// **What it does:** Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
224     ///
225     /// **Why is this bad?** Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
226     /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
227     ///
228     /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
229     /// works if there are no additional references yet, which usually defeats the purpose of
230     /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
231     /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
232     /// be used.
233     ///
234     /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
235     /// cases where mutation only happens before there are any additional references.
236     ///
237     /// **Example:**
238     /// ```rust,ignore
239     /// # use std::rc::Rc;
240     /// fn foo(interned: Rc<String>) { ... }
241     /// ```
242     ///
243     /// Better:
244     ///
245     /// ```rust,ignore
246     /// fn foo(interned: Rc<str>) { ... }
247     /// ```
248     pub RC_BUFFER,
249     restriction,
250     "shared ownership of a buffer type"
251 }
252
253 pub struct Types {
254     vec_box_size_threshold: u64,
255 }
256
257 impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]);
258
259 impl<'tcx> LateLintPass<'tcx> for Types {
260     fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
261         // Skip trait implementations; see issue #605.
262         if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id)) {
263             if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
264                 return;
265             }
266         }
267
268         self.check_fn_decl(cx, decl);
269     }
270
271     fn check_struct_field(&mut self, cx: &LateContext<'_>, field: &hir::StructField<'_>) {
272         self.check_ty(cx, &field.ty, false);
273     }
274
275     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
276         match item.kind {
277             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_ty(cx, ty, false),
278             TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl),
279             _ => (),
280         }
281     }
282
283     fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
284         if let Some(ref ty) = local.ty {
285             self.check_ty(cx, ty, true);
286         }
287     }
288 }
289
290 fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
291     if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() {
292         Some("str")
293     } else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() {
294         Some("std::ffi::OsStr")
295     } else if is_ty_param_diagnostic_item(cx, qpath, sym::PathBuf).is_some() {
296         Some("std::path::Path")
297     } else {
298         None
299     }
300 }
301
302 fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
303     let last = last_path_segment(qpath);
304     if_chain! {
305         if let Some(ref params) = last.args;
306         if !params.parenthesized;
307         if let Some(ty) = params.args.iter().find_map(|arg| match arg {
308             GenericArg::Type(ty) => Some(ty),
309             _ => None,
310         });
311         if let TyKind::Rptr(..) = ty.kind;
312         then {
313             return Some(ty.span);
314         }
315     }
316     None
317 }
318
319 impl Types {
320     pub fn new(vec_box_size_threshold: u64) -> Self {
321         Self { vec_box_size_threshold }
322     }
323
324     fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>) {
325         for input in decl.inputs {
326             self.check_ty(cx, input, false);
327         }
328
329         if let FnRetTy::Return(ref ty) = decl.output {
330             self.check_ty(cx, ty, false);
331         }
332     }
333
334     /// Recursively check for `TypePass` lints in the given type. Stop at the first
335     /// lint found.
336     ///
337     /// The parameter `is_local` distinguishes the context of the type; types from
338     /// local bindings should only be checked for the `BORROWED_BOX` lint.
339     #[allow(clippy::too_many_lines)]
340     fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, is_local: bool) {
341         if hir_ty.span.from_expansion() {
342             return;
343         }
344         match hir_ty.kind {
345             TyKind::Path(ref qpath) if !is_local => {
346                 let hir_id = hir_ty.hir_id;
347                 let res = cx.qpath_res(qpath, hir_id);
348                 if let Some(def_id) = res.opt_def_id() {
349                     if Some(def_id) == cx.tcx.lang_items().owned_box() {
350                         if let Some(span) = match_borrows_parameter(cx, qpath) {
351                             let mut applicability = Applicability::MachineApplicable;
352                             span_lint_and_sugg(
353                                 cx,
354                                 REDUNDANT_ALLOCATION,
355                                 hir_ty.span,
356                                 "usage of `Box<&T>`",
357                                 "try",
358                                 snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
359                                 applicability,
360                             );
361                             return; // don't recurse into the type
362                         }
363                         if is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some() {
364                             span_lint_and_help(
365                                 cx,
366                                 BOX_VEC,
367                                 hir_ty.span,
368                                 "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
369                                 None,
370                                 "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation",
371                             );
372                             return; // don't recurse into the type
373                         }
374                     } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
375                         if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
376                             let mut applicability = Applicability::MachineApplicable;
377                             span_lint_and_sugg(
378                                 cx,
379                                 REDUNDANT_ALLOCATION,
380                                 hir_ty.span,
381                                 "usage of `Rc<Rc<T>>`",
382                                 "try",
383                                 snippet_with_applicability(cx, ty.span, "..", &mut applicability).to_string(),
384                                 applicability,
385                             );
386                             return; // don't recurse into the type
387                         }
388                         if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
389                             let qpath = match &ty.kind {
390                                 TyKind::Path(qpath) => qpath,
391                                 _ => return,
392                             };
393                             let inner_span = match get_qpath_generic_tys(qpath).next() {
394                                 Some(ty) => ty.span,
395                                 None => return,
396                             };
397                             let mut applicability = Applicability::MachineApplicable;
398                             span_lint_and_sugg(
399                                 cx,
400                                 REDUNDANT_ALLOCATION,
401                                 hir_ty.span,
402                                 "usage of `Rc<Box<T>>`",
403                                 "try",
404                                 format!(
405                                     "Rc<{}>",
406                                     snippet_with_applicability(cx, inner_span, "..", &mut applicability)
407                                 ),
408                                 applicability,
409                             );
410                             return; // don't recurse into the type
411                         }
412                         if let Some(alternate) = match_buffer_type(cx, qpath) {
413                             span_lint_and_sugg(
414                                 cx,
415                                 RC_BUFFER,
416                                 hir_ty.span,
417                                 "usage of `Rc<T>` when T is a buffer type",
418                                 "try",
419                                 format!("Rc<{}>", alternate),
420                                 Applicability::MachineApplicable,
421                             );
422                             return; // don't recurse into the type
423                         }
424                         if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::vec_type) {
425                             let qpath = match &ty.kind {
426                                 TyKind::Path(qpath) => qpath,
427                                 _ => return,
428                             };
429                             let inner_span = match get_qpath_generic_tys(qpath).next() {
430                                 Some(ty) => ty.span,
431                                 None => return,
432                             };
433                             let mut applicability = Applicability::MachineApplicable;
434                             span_lint_and_sugg(
435                                 cx,
436                                 RC_BUFFER,
437                                 hir_ty.span,
438                                 "usage of `Rc<T>` when T is a buffer type",
439                                 "try",
440                                 format!(
441                                     "Rc<[{}]>",
442                                     snippet_with_applicability(cx, inner_span, "..", &mut applicability)
443                                 ),
444                                 Applicability::MachineApplicable,
445                             );
446                             return; // don't recurse into the type
447                         }
448                         if let Some(span) = match_borrows_parameter(cx, qpath) {
449                             let mut applicability = Applicability::MachineApplicable;
450                             span_lint_and_sugg(
451                                 cx,
452                                 REDUNDANT_ALLOCATION,
453                                 hir_ty.span,
454                                 "usage of `Rc<&T>`",
455                                 "try",
456                                 snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
457                                 applicability,
458                             );
459                             return; // don't recurse into the type
460                         }
461                     } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
462                         if let Some(alternate) = match_buffer_type(cx, qpath) {
463                             span_lint_and_sugg(
464                                 cx,
465                                 RC_BUFFER,
466                                 hir_ty.span,
467                                 "usage of `Arc<T>` when T is a buffer type",
468                                 "try",
469                                 format!("Arc<{}>", alternate),
470                                 Applicability::MachineApplicable,
471                             );
472                             return; // don't recurse into the type
473                         }
474                         if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::vec_type) {
475                             let qpath = match &ty.kind {
476                                 TyKind::Path(qpath) => qpath,
477                                 _ => return,
478                             };
479                             let inner_span = match get_qpath_generic_tys(qpath).next() {
480                                 Some(ty) => ty.span,
481                                 None => return,
482                             };
483                             let mut applicability = Applicability::MachineApplicable;
484                             span_lint_and_sugg(
485                                 cx,
486                                 RC_BUFFER,
487                                 hir_ty.span,
488                                 "usage of `Arc<T>` when T is a buffer type",
489                                 "try",
490                                 format!(
491                                     "Arc<[{}]>",
492                                     snippet_with_applicability(cx, inner_span, "..", &mut applicability)
493                                 ),
494                                 Applicability::MachineApplicable,
495                             );
496                             return; // don't recurse into the type
497                         }
498                     } else if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) {
499                         if_chain! {
500                             // Get the _ part of Vec<_>
501                             if let Some(ref last) = last_path_segment(qpath).args;
502                             if let Some(ty) = last.args.iter().find_map(|arg| match arg {
503                                 GenericArg::Type(ty) => Some(ty),
504                                 _ => None,
505                             });
506                             // ty is now _ at this point
507                             if let TyKind::Path(ref ty_qpath) = ty.kind;
508                             let res = cx.qpath_res(ty_qpath, ty.hir_id);
509                             if let Some(def_id) = res.opt_def_id();
510                             if Some(def_id) == cx.tcx.lang_items().owned_box();
511                             // At this point, we know ty is Box<T>, now get T
512                             if let Some(ref last) = last_path_segment(ty_qpath).args;
513                             if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
514                                 GenericArg::Type(ty) => Some(ty),
515                                 _ => None,
516                             });
517                             let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
518                             if !ty_ty.has_escaping_bound_vars();
519                             if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env);
520                             if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
521                             if ty_ty_size <= self.vec_box_size_threshold;
522                             then {
523                                 span_lint_and_sugg(
524                                     cx,
525                                     VEC_BOX,
526                                     hir_ty.span,
527                                     "`Vec<T>` is already on the heap, the boxing is unnecessary",
528                                     "try",
529                                     format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
530                                     Applicability::MachineApplicable,
531                                 );
532                                 return; // don't recurse into the type
533                             }
534                         }
535                     } else if cx.tcx.is_diagnostic_item(sym::option_type, def_id) {
536                         if is_ty_param_diagnostic_item(cx, qpath, sym::option_type).is_some() {
537                             span_lint(
538                                 cx,
539                                 OPTION_OPTION,
540                                 hir_ty.span,
541                                 "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
542                                  enum if you need to distinguish all 3 cases",
543                             );
544                             return; // don't recurse into the type
545                         }
546                     } else if match_def_path(cx, def_id, &paths::LINKED_LIST) {
547                         span_lint_and_help(
548                             cx,
549                             LINKEDLIST,
550                             hir_ty.span,
551                             "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?",
552                             None,
553                             "a `VecDeque` might work",
554                         );
555                         return; // don't recurse into the type
556                     }
557                 }
558                 match *qpath {
559                     QPath::Resolved(Some(ref ty), ref p) => {
560                         self.check_ty(cx, ty, is_local);
561                         for ty in p.segments.iter().flat_map(|seg| {
562                             seg.args
563                                 .as_ref()
564                                 .map_or_else(|| [].iter(), |params| params.args.iter())
565                                 .filter_map(|arg| match arg {
566                                     GenericArg::Type(ty) => Some(ty),
567                                     _ => None,
568                                 })
569                         }) {
570                             self.check_ty(cx, ty, is_local);
571                         }
572                     },
573                     QPath::Resolved(None, ref p) => {
574                         for ty in p.segments.iter().flat_map(|seg| {
575                             seg.args
576                                 .as_ref()
577                                 .map_or_else(|| [].iter(), |params| params.args.iter())
578                                 .filter_map(|arg| match arg {
579                                     GenericArg::Type(ty) => Some(ty),
580                                     _ => None,
581                                 })
582                         }) {
583                             self.check_ty(cx, ty, is_local);
584                         }
585                     },
586                     QPath::TypeRelative(ref ty, ref seg) => {
587                         self.check_ty(cx, ty, is_local);
588                         if let Some(ref params) = seg.args {
589                             for ty in params.args.iter().filter_map(|arg| match arg {
590                                 GenericArg::Type(ty) => Some(ty),
591                                 _ => None,
592                             }) {
593                                 self.check_ty(cx, ty, is_local);
594                             }
595                         }
596                     },
597                     QPath::LangItem(..) => {},
598                 }
599             },
600             TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
601             // recurse
602             TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => {
603                 self.check_ty(cx, ty, is_local)
604             },
605             TyKind::Tup(tys) => {
606                 for ty in tys {
607                     self.check_ty(cx, ty, is_local);
608                 }
609             },
610             _ => {},
611         }
612     }
613
614     fn check_ty_rptr(
615         &mut self,
616         cx: &LateContext<'_>,
617         hir_ty: &hir::Ty<'_>,
618         is_local: bool,
619         lt: &Lifetime,
620         mut_ty: &MutTy<'_>,
621     ) {
622         match mut_ty.ty.kind {
623             TyKind::Path(ref qpath) => {
624                 let hir_id = mut_ty.ty.hir_id;
625                 let def = cx.qpath_res(qpath, hir_id);
626                 if_chain! {
627                     if let Some(def_id) = def.opt_def_id();
628                     if Some(def_id) == cx.tcx.lang_items().owned_box();
629                     if let QPath::Resolved(None, ref path) = *qpath;
630                     if let [ref bx] = *path.segments;
631                     if let Some(ref params) = bx.args;
632                     if !params.parenthesized;
633                     if let Some(inner) = params.args.iter().find_map(|arg| match arg {
634                         GenericArg::Type(ty) => Some(ty),
635                         _ => None,
636                     });
637                     then {
638                         if is_any_trait(inner) {
639                             // Ignore `Box<Any>` types; see issue #1884 for details.
640                             return;
641                         }
642
643                         let ltopt = if lt.is_elided() {
644                             String::new()
645                         } else {
646                             format!("{} ", lt.name.ident().as_str())
647                         };
648
649                         if mut_ty.mutbl == Mutability::Mut {
650                             // Ignore `&mut Box<T>` types; see issue #2907 for
651                             // details.
652                             return;
653                         }
654
655                         // When trait objects or opaque types have lifetime or auto-trait bounds,
656                         // we need to add parentheses to avoid a syntax error due to its ambiguity.
657                         // Originally reported as the issue #3128.
658                         let inner_snippet = snippet(cx, inner.span, "..");
659                         let suggestion = match &inner.kind {
660                             TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => {
661                                 format!("&{}({})", ltopt, &inner_snippet)
662                             },
663                             TyKind::Path(qpath)
664                                 if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
665                                     .map_or(false, |bounds| bounds.len() > 1) =>
666                             {
667                                 format!("&{}({})", ltopt, &inner_snippet)
668                             },
669                             _ => format!("&{}{}", ltopt, &inner_snippet),
670                         };
671                         span_lint_and_sugg(
672                             cx,
673                             BORROWED_BOX,
674                             hir_ty.span,
675                             "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
676                             "try",
677                             suggestion,
678                             // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
679                             // because the trait impls of it will break otherwise;
680                             // and there may be other cases that result in invalid code.
681                             // For example, type coercion doesn't work nicely.
682                             Applicability::Unspecified,
683                         );
684                         return; // don't recurse into the type
685                     }
686                 };
687                 self.check_ty(cx, &mut_ty.ty, is_local);
688             },
689             _ => self.check_ty(cx, &mut_ty.ty, is_local),
690         }
691     }
692 }
693
694 // Returns true if given type is `Any` trait.
695 fn is_any_trait(t: &hir::Ty<'_>) -> bool {
696     if_chain! {
697         if let TyKind::TraitObject(ref traits, _) = t.kind;
698         if !traits.is_empty();
699         // Only Send/Sync can be used as additional traits, so it is enough to
700         // check only the first trait.
701         if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
702         then {
703             return true;
704         }
705     }
706
707     false
708 }
709
710 fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
711     if_chain! {
712         if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
713         if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
714         if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
715         if synthetic == Some(SyntheticTyParamKind::ImplTrait);
716         then {
717             Some(generic_param.bounds)
718         } else {
719             None
720         }
721     }
722 }
723
724 declare_clippy_lint! {
725     /// **What it does:** Checks for binding a unit value.
726     ///
727     /// **Why is this bad?** A unit value cannot usefully be used anywhere. So
728     /// binding one is kind of pointless.
729     ///
730     /// **Known problems:** None.
731     ///
732     /// **Example:**
733     /// ```rust
734     /// let x = {
735     ///     1;
736     /// };
737     /// ```
738     pub LET_UNIT_VALUE,
739     pedantic,
740     "creating a `let` binding to a value of unit type, which usually can't be used afterwards"
741 }
742
743 declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]);
744
745 impl<'tcx> LateLintPass<'tcx> for LetUnitValue {
746     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
747         if let StmtKind::Local(ref local) = stmt.kind {
748             if is_unit(cx.typeck_results().pat_ty(&local.pat)) {
749                 if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
750                     return;
751                 }
752                 if higher::is_from_for_desugar(local) {
753                     return;
754                 }
755                 span_lint_and_then(
756                     cx,
757                     LET_UNIT_VALUE,
758                     stmt.span,
759                     "this let-binding has unit value",
760                     |diag| {
761                         if let Some(expr) = &local.init {
762                             let snip = snippet_with_macro_callsite(cx, expr.span, "()");
763                             diag.span_suggestion(
764                                 stmt.span,
765                                 "omit the `let` binding",
766                                 format!("{};", snip),
767                                 Applicability::MachineApplicable, // snippet
768                             );
769                         }
770                     },
771                 );
772             }
773         }
774     }
775 }
776
777 declare_clippy_lint! {
778     /// **What it does:** Checks for comparisons to unit. This includes all binary
779     /// comparisons (like `==` and `<`) and asserts.
780     ///
781     /// **Why is this bad?** Unit is always equal to itself, and thus is just a
782     /// clumsily written constant. Mostly this happens when someone accidentally
783     /// adds semicolons at the end of the operands.
784     ///
785     /// **Known problems:** None.
786     ///
787     /// **Example:**
788     /// ```rust
789     /// # fn foo() {};
790     /// # fn bar() {};
791     /// # fn baz() {};
792     /// if {
793     ///     foo();
794     /// } == {
795     ///     bar();
796     /// } {
797     ///     baz();
798     /// }
799     /// ```
800     /// is equal to
801     /// ```rust
802     /// # fn foo() {};
803     /// # fn bar() {};
804     /// # fn baz() {};
805     /// {
806     ///     foo();
807     ///     bar();
808     ///     baz();
809     /// }
810     /// ```
811     ///
812     /// For asserts:
813     /// ```rust
814     /// # fn foo() {};
815     /// # fn bar() {};
816     /// assert_eq!({ foo(); }, { bar(); });
817     /// ```
818     /// will always succeed
819     pub UNIT_CMP,
820     correctness,
821     "comparing unit values"
822 }
823
824 declare_lint_pass!(UnitCmp => [UNIT_CMP]);
825
826 impl<'tcx> LateLintPass<'tcx> for UnitCmp {
827     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
828         if expr.span.from_expansion() {
829             if let Some(callee) = expr.span.source_callee() {
830                 if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
831                     if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
832                         let op = cmp.node;
833                         if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
834                             let result = match &*symbol.as_str() {
835                                 "assert_eq" | "debug_assert_eq" => "succeed",
836                                 "assert_ne" | "debug_assert_ne" => "fail",
837                                 _ => return,
838                             };
839                             span_lint(
840                                 cx,
841                                 UNIT_CMP,
842                                 expr.span,
843                                 &format!(
844                                     "`{}` of unit values detected. This will always {}",
845                                     symbol.as_str(),
846                                     result
847                                 ),
848                             );
849                         }
850                     }
851                 }
852             }
853             return;
854         }
855         if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
856             let op = cmp.node;
857             if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
858                 let result = match op {
859                     BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
860                     _ => "false",
861                 };
862                 span_lint(
863                     cx,
864                     UNIT_CMP,
865                     expr.span,
866                     &format!(
867                         "{}-comparison of unit values detected. This will always be {}",
868                         op.as_str(),
869                         result
870                     ),
871                 );
872             }
873         }
874     }
875 }
876
877 declare_clippy_lint! {
878     /// **What it does:** Checks for passing a unit value as an argument to a function without using a
879     /// unit literal (`()`).
880     ///
881     /// **Why is this bad?** This is likely the result of an accidental semicolon.
882     ///
883     /// **Known problems:** None.
884     ///
885     /// **Example:**
886     /// ```rust,ignore
887     /// foo({
888     ///     let a = bar();
889     ///     baz(a);
890     /// })
891     /// ```
892     pub UNIT_ARG,
893     complexity,
894     "passing unit to a function"
895 }
896
897 declare_lint_pass!(UnitArg => [UNIT_ARG]);
898
899 impl<'tcx> LateLintPass<'tcx> for UnitArg {
900     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
901         if expr.span.from_expansion() {
902             return;
903         }
904
905         // apparently stuff in the desugaring of `?` can trigger this
906         // so check for that here
907         // only the calls to `Try::from_error` is marked as desugared,
908         // so we need to check both the current Expr and its parent.
909         if is_questionmark_desugar_marked_call(expr) {
910             return;
911         }
912         if_chain! {
913             let map = &cx.tcx.hir();
914             let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
915             if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
916             if is_questionmark_desugar_marked_call(parent_expr);
917             then {
918                 return;
919             }
920         }
921
922         match expr.kind {
923             ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => {
924                 let args_to_recover = args
925                     .iter()
926                     .filter(|arg| {
927                         if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) {
928                             !matches!(
929                                 &arg.kind,
930                                 ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
931                             )
932                         } else {
933                             false
934                         }
935                     })
936                     .collect::<Vec<_>>();
937                 if !args_to_recover.is_empty() {
938                     lint_unit_args(cx, expr, &args_to_recover);
939                 }
940             },
941             _ => (),
942         }
943     }
944 }
945
946 fn fmt_stmts_and_call(
947     cx: &LateContext<'_>,
948     call_expr: &Expr<'_>,
949     call_snippet: &str,
950     args_snippets: &[impl AsRef<str>],
951     non_empty_block_args_snippets: &[impl AsRef<str>],
952 ) -> String {
953     let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
954     let call_snippet_with_replacements = args_snippets
955         .iter()
956         .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1));
957
958     let mut stmts_and_call = non_empty_block_args_snippets
959         .iter()
960         .map(|it| it.as_ref().to_owned())
961         .collect::<Vec<_>>();
962     stmts_and_call.push(call_snippet_with_replacements);
963     stmts_and_call = stmts_and_call
964         .into_iter()
965         .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned())
966         .collect();
967
968     let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
969     // expr is not in a block statement or result expression position, wrap in a block
970     let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id));
971     if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
972         let block_indent = call_expr_indent + 4;
973         stmts_and_call_snippet =
974             reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();
975         stmts_and_call_snippet = format!(
976             "{{\n{}{}\n{}}}",
977             " ".repeat(block_indent),
978             &stmts_and_call_snippet,
979             " ".repeat(call_expr_indent)
980         );
981     }
982     stmts_and_call_snippet
983 }
984
985 fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
986     let mut applicability = Applicability::MachineApplicable;
987     let (singular, plural) = if args_to_recover.len() > 1 {
988         ("", "s")
989     } else {
990         ("a ", "")
991     };
992     span_lint_and_then(
993         cx,
994         UNIT_ARG,
995         expr.span,
996         &format!("passing {}unit value{} to a function", singular, plural),
997         |db| {
998             let mut or = "";
999             args_to_recover
1000                 .iter()
1001                 .filter_map(|arg| {
1002                     if_chain! {
1003                         if let ExprKind::Block(block, _) = arg.kind;
1004                         if block.expr.is_none();
1005                         if let Some(last_stmt) = block.stmts.iter().last();
1006                         if let StmtKind::Semi(last_expr) = last_stmt.kind;
1007                         if let Some(snip) = snippet_opt(cx, last_expr.span);
1008                         then {
1009                             Some((
1010                                 last_stmt.span,
1011                                 snip,
1012                             ))
1013                         }
1014                         else {
1015                             None
1016                         }
1017                     }
1018                 })
1019                 .for_each(|(span, sugg)| {
1020                     db.span_suggestion(
1021                         span,
1022                         "remove the semicolon from the last statement in the block",
1023                         sugg,
1024                         Applicability::MaybeIncorrect,
1025                     );
1026                     or = "or ";
1027                     applicability = Applicability::MaybeIncorrect;
1028                 });
1029
1030             let arg_snippets: Vec<String> = args_to_recover
1031                 .iter()
1032                 .filter_map(|arg| snippet_opt(cx, arg.span))
1033                 .collect();
1034             let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover
1035                 .iter()
1036                 .filter(|arg| !is_empty_block(arg))
1037                 .filter_map(|arg| snippet_opt(cx, arg.span))
1038                 .collect();
1039
1040             if let Some(call_snippet) = snippet_opt(cx, expr.span) {
1041                 let sugg = fmt_stmts_and_call(
1042                     cx,
1043                     expr,
1044                     &call_snippet,
1045                     &arg_snippets,
1046                     &arg_snippets_without_empty_blocks,
1047                 );
1048
1049                 if arg_snippets_without_empty_blocks.is_empty() {
1050                     db.multipart_suggestion(
1051                         &format!("use {}unit literal{} instead", singular, plural),
1052                         args_to_recover
1053                             .iter()
1054                             .map(|arg| (arg.span, "()".to_string()))
1055                             .collect::<Vec<_>>(),
1056                         applicability,
1057                     );
1058                 } else {
1059                     let plural = arg_snippets_without_empty_blocks.len() > 1;
1060                     let empty_or_s = if plural { "s" } else { "" };
1061                     let it_or_them = if plural { "them" } else { "it" };
1062                     db.span_suggestion(
1063                         expr.span,
1064                         &format!(
1065                             "{}move the expression{} in front of the call and replace {} with the unit literal `()`",
1066                             or, empty_or_s, it_or_them
1067                         ),
1068                         sugg,
1069                         applicability,
1070                     );
1071                 }
1072             }
1073         },
1074     );
1075 }
1076
1077 fn is_empty_block(expr: &Expr<'_>) -> bool {
1078     matches!(
1079         expr.kind,
1080         ExprKind::Block(
1081             Block {
1082                 stmts: &[],
1083                 expr: None,
1084                 ..
1085             },
1086             _,
1087         )
1088     )
1089 }
1090
1091 fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
1092     use rustc_span::hygiene::DesugaringKind;
1093     if let ExprKind::Call(ref callee, _) = expr.kind {
1094         callee.span.is_desugaring(DesugaringKind::QuestionMark)
1095     } else {
1096         false
1097     }
1098 }
1099
1100 fn is_unit(ty: Ty<'_>) -> bool {
1101     matches!(ty.kind(), ty::Tuple(slice) if slice.is_empty())
1102 }
1103
1104 fn is_unit_literal(expr: &Expr<'_>) -> bool {
1105     matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty())
1106 }
1107
1108 declare_clippy_lint! {
1109     /// **What it does:** Checks for casts from any numerical to a float type where
1110     /// the receiving type cannot store all values from the original type without
1111     /// rounding errors. This possible rounding is to be expected, so this lint is
1112     /// `Allow` by default.
1113     ///
1114     /// Basically, this warns on casting any integer with 32 or more bits to `f32`
1115     /// or any 64-bit integer to `f64`.
1116     ///
1117     /// **Why is this bad?** It's not bad at all. But in some applications it can be
1118     /// helpful to know where precision loss can take place. This lint can help find
1119     /// those places in the code.
1120     ///
1121     /// **Known problems:** None.
1122     ///
1123     /// **Example:**
1124     /// ```rust
1125     /// let x = u64::MAX;
1126     /// x as f64;
1127     /// ```
1128     pub CAST_PRECISION_LOSS,
1129     pedantic,
1130     "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
1131 }
1132
1133 declare_clippy_lint! {
1134     /// **What it does:** Checks for casts from a signed to an unsigned numerical
1135     /// type. In this case, negative values wrap around to large positive values,
1136     /// which can be quite surprising in practice. However, as the cast works as
1137     /// defined, this lint is `Allow` by default.
1138     ///
1139     /// **Why is this bad?** Possibly surprising results. You can activate this lint
1140     /// as a one-time check to see where numerical wrapping can arise.
1141     ///
1142     /// **Known problems:** None.
1143     ///
1144     /// **Example:**
1145     /// ```rust
1146     /// let y: i8 = -1;
1147     /// y as u128; // will return 18446744073709551615
1148     /// ```
1149     pub CAST_SIGN_LOSS,
1150     pedantic,
1151     "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
1152 }
1153
1154 declare_clippy_lint! {
1155     /// **What it does:** Checks for casts between numerical types that may
1156     /// truncate large values. This is expected behavior, so the cast is `Allow` by
1157     /// default.
1158     ///
1159     /// **Why is this bad?** In some problem domains, it is good practice to avoid
1160     /// truncation. This lint can be activated to help assess where additional
1161     /// checks could be beneficial.
1162     ///
1163     /// **Known problems:** None.
1164     ///
1165     /// **Example:**
1166     /// ```rust
1167     /// fn as_u8(x: u64) -> u8 {
1168     ///     x as u8
1169     /// }
1170     /// ```
1171     pub CAST_POSSIBLE_TRUNCATION,
1172     pedantic,
1173     "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
1174 }
1175
1176 declare_clippy_lint! {
1177     /// **What it does:** Checks for casts from an unsigned type to a signed type of
1178     /// the same size. Performing such a cast is a 'no-op' for the compiler,
1179     /// i.e., nothing is changed at the bit level, and the binary representation of
1180     /// the value is reinterpreted. This can cause wrapping if the value is too big
1181     /// for the target signed type. However, the cast works as defined, so this lint
1182     /// is `Allow` by default.
1183     ///
1184     /// **Why is this bad?** While such a cast is not bad in itself, the results can
1185     /// be surprising when this is not the intended behavior, as demonstrated by the
1186     /// example below.
1187     ///
1188     /// **Known problems:** None.
1189     ///
1190     /// **Example:**
1191     /// ```rust
1192     /// u32::MAX as i32; // will yield a value of `-1`
1193     /// ```
1194     pub CAST_POSSIBLE_WRAP,
1195     pedantic,
1196     "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
1197 }
1198
1199 declare_clippy_lint! {
1200     /// **What it does:** Checks for casts between numerical types that may
1201     /// be replaced by safe conversion functions.
1202     ///
1203     /// **Why is this bad?** Rust's `as` keyword will perform many kinds of
1204     /// conversions, including silently lossy conversions. Conversion functions such
1205     /// as `i32::from` will only perform lossless conversions. Using the conversion
1206     /// functions prevents conversions from turning into silent lossy conversions if
1207     /// the types of the input expressions ever change, and make it easier for
1208     /// people reading the code to know that the conversion is lossless.
1209     ///
1210     /// **Known problems:** None.
1211     ///
1212     /// **Example:**
1213     /// ```rust
1214     /// fn as_u64(x: u8) -> u64 {
1215     ///     x as u64
1216     /// }
1217     /// ```
1218     ///
1219     /// Using `::from` would look like this:
1220     ///
1221     /// ```rust
1222     /// fn as_u64(x: u8) -> u64 {
1223     ///     u64::from(x)
1224     /// }
1225     /// ```
1226     pub CAST_LOSSLESS,
1227     pedantic,
1228     "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
1229 }
1230
1231 declare_clippy_lint! {
1232     /// **What it does:** Checks for casts to the same type, casts of int literals to integer types
1233     /// and casts of float literals to float types.
1234     ///
1235     /// **Why is this bad?** It's just unnecessary.
1236     ///
1237     /// **Known problems:** None.
1238     ///
1239     /// **Example:**
1240     /// ```rust
1241     /// let _ = 2i32 as i32;
1242     /// let _ = 0.5 as f32;
1243     /// ```
1244     ///
1245     /// Better:
1246     ///
1247     /// ```rust
1248     /// let _ = 2_i32;
1249     /// let _ = 0.5_f32;
1250     /// ```
1251     pub UNNECESSARY_CAST,
1252     complexity,
1253     "cast to the same type, e.g., `x as i32` where `x: i32`"
1254 }
1255
1256 declare_clippy_lint! {
1257     /// **What it does:** Checks for casts, using `as` or `pointer::cast`,
1258     /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
1259     ///
1260     /// **Why is this bad?** Dereferencing the resulting pointer may be undefined
1261     /// behavior.
1262     ///
1263     /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
1264     /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
1265     /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
1266     ///
1267     /// **Example:**
1268     /// ```rust
1269     /// let _ = (&1u8 as *const u8) as *const u16;
1270     /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
1271     ///
1272     /// (&1u8 as *const u8).cast::<u16>();
1273     /// (&mut 1u8 as *mut u8).cast::<u16>();
1274     /// ```
1275     pub CAST_PTR_ALIGNMENT,
1276     pedantic,
1277     "cast from a pointer to a more-strictly-aligned pointer"
1278 }
1279
1280 declare_clippy_lint! {
1281     /// **What it does:** Checks for casts of function pointers to something other than usize
1282     ///
1283     /// **Why is this bad?**
1284     /// Casting a function pointer to anything other than usize/isize is not portable across
1285     /// architectures, because you end up losing bits if the target type is too small or end up with a
1286     /// bunch of extra bits that waste space and add more instructions to the final binary than
1287     /// strictly necessary for the problem
1288     ///
1289     /// Casting to isize also doesn't make sense since there are no signed addresses.
1290     ///
1291     /// **Example**
1292     ///
1293     /// ```rust
1294     /// // Bad
1295     /// fn fun() -> i32 { 1 }
1296     /// let a = fun as i64;
1297     ///
1298     /// // Good
1299     /// fn fun2() -> i32 { 1 }
1300     /// let a = fun2 as usize;
1301     /// ```
1302     pub FN_TO_NUMERIC_CAST,
1303     style,
1304     "casting a function pointer to a numeric type other than usize"
1305 }
1306
1307 declare_clippy_lint! {
1308     /// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to
1309     /// store address.
1310     ///
1311     /// **Why is this bad?**
1312     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
1313     /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
1314     /// a comment) to perform the truncation.
1315     ///
1316     /// **Example**
1317     ///
1318     /// ```rust
1319     /// // Bad
1320     /// fn fn1() -> i16 {
1321     ///     1
1322     /// };
1323     /// let _ = fn1 as i32;
1324     ///
1325     /// // Better: Cast to usize first, then comment with the reason for the truncation
1326     /// fn fn2() -> i16 {
1327     ///     1
1328     /// };
1329     /// let fn_ptr = fn2 as usize;
1330     /// let fn_ptr_truncated = fn_ptr as i32;
1331     /// ```
1332     pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
1333     style,
1334     "casting a function pointer to a numeric type not wide enough to store the address"
1335 }
1336
1337 /// Returns the size in bits of an integral type.
1338 /// Will return 0 if the type is not an int or uint variant
1339 fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
1340     match typ.kind() {
1341         ty::Int(i) => match i {
1342             IntTy::Isize => tcx.data_layout.pointer_size.bits(),
1343             IntTy::I8 => 8,
1344             IntTy::I16 => 16,
1345             IntTy::I32 => 32,
1346             IntTy::I64 => 64,
1347             IntTy::I128 => 128,
1348         },
1349         ty::Uint(i) => match i {
1350             UintTy::Usize => tcx.data_layout.pointer_size.bits(),
1351             UintTy::U8 => 8,
1352             UintTy::U16 => 16,
1353             UintTy::U32 => 32,
1354             UintTy::U64 => 64,
1355             UintTy::U128 => 128,
1356         },
1357         _ => 0,
1358     }
1359 }
1360
1361 fn is_isize_or_usize(typ: Ty<'_>) -> bool {
1362     matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
1363 }
1364
1365 fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) {
1366     let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
1367     let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
1368     let arch_dependent_str = "on targets with 64-bit wide pointers ";
1369     let from_nbits_str = if arch_dependent {
1370         "64".to_owned()
1371     } else if is_isize_or_usize(cast_from) {
1372         "32 or 64".to_owned()
1373     } else {
1374         int_ty_to_nbits(cast_from, cx.tcx).to_string()
1375     };
1376     span_lint(
1377         cx,
1378         CAST_PRECISION_LOSS,
1379         expr.span,
1380         &format!(
1381             "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
1382              but `{1}`'s mantissa is only {4} bits wide)",
1383             cast_from,
1384             if cast_to_f64 { "f64" } else { "f32" },
1385             if arch_dependent { arch_dependent_str } else { "" },
1386             from_nbits_str,
1387             mantissa_nbits
1388         ),
1389     );
1390 }
1391
1392 fn should_strip_parens(op: &Expr<'_>, snip: &str) -> bool {
1393     if let ExprKind::Binary(_, _, _) = op.kind {
1394         if snip.starts_with('(') && snip.ends_with(')') {
1395             return true;
1396         }
1397     }
1398     false
1399 }
1400
1401 fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1402     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
1403     if in_constant(cx, expr.hir_id) {
1404         return;
1405     }
1406     // The suggestion is to use a function call, so if the original expression
1407     // has parens on the outside, they are no longer needed.
1408     let mut applicability = Applicability::MachineApplicable;
1409     let opt = snippet_opt(cx, op.span);
1410     let sugg = opt.as_ref().map_or_else(
1411         || {
1412             applicability = Applicability::HasPlaceholders;
1413             ".."
1414         },
1415         |snip| {
1416             if should_strip_parens(op, snip) {
1417                 &snip[1..snip.len() - 1]
1418             } else {
1419                 snip.as_str()
1420             }
1421         },
1422     );
1423
1424     span_lint_and_sugg(
1425         cx,
1426         CAST_LOSSLESS,
1427         expr.span,
1428         &format!(
1429             "casting `{}` to `{}` may become silently lossy if you later change the type",
1430             cast_from, cast_to
1431         ),
1432         "try",
1433         format!("{}::from({})", cast_to, sugg),
1434         applicability,
1435     );
1436 }
1437
1438 enum ArchSuffix {
1439     _32,
1440     _64,
1441     None,
1442 }
1443
1444 fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1445     if !cast_from.is_signed() || cast_to.is_signed() {
1446         return;
1447     }
1448
1449     // don't lint for positive constants
1450     let const_val = constant(cx, &cx.typeck_results(), op);
1451     if_chain! {
1452         if let Some((Constant::Int(n), _)) = const_val;
1453         if let ty::Int(ity) = *cast_from.kind();
1454         if sext(cx.tcx, n, ity) >= 0;
1455         then {
1456             return
1457         }
1458     }
1459
1460     // don't lint for the result of methods that always return non-negative values
1461     if let ExprKind::MethodCall(ref path, _, _, _) = op.kind {
1462         let mut method_name = path.ident.name.as_str();
1463         let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
1464
1465         if_chain! {
1466             if method_name == "unwrap";
1467             if let Some(arglist) = method_chain_args(op, &["unwrap"]);
1468             if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind;
1469             then {
1470                 method_name = inner_path.ident.name.as_str();
1471             }
1472         }
1473
1474         if allowed_methods.iter().any(|&name| method_name == name) {
1475             return;
1476         }
1477     }
1478
1479     span_lint(
1480         cx,
1481         CAST_SIGN_LOSS,
1482         expr.span,
1483         &format!(
1484             "casting `{}` to `{}` may lose the sign of the value",
1485             cast_from, cast_to
1486         ),
1487     );
1488 }
1489
1490 fn check_truncation_and_wrapping(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1491     let arch_64_suffix = " on targets with 64-bit wide pointers";
1492     let arch_32_suffix = " on targets with 32-bit wide pointers";
1493     let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
1494     let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
1495     let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1496     let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) =
1497         match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
1498             (true, true) | (false, false) => (
1499                 to_nbits < from_nbits,
1500                 ArchSuffix::None,
1501                 to_nbits == from_nbits && cast_unsigned_to_signed,
1502                 ArchSuffix::None,
1503             ),
1504             (true, false) => (
1505                 to_nbits <= 32,
1506                 if to_nbits == 32 {
1507                     ArchSuffix::_64
1508                 } else {
1509                     ArchSuffix::None
1510                 },
1511                 to_nbits <= 32 && cast_unsigned_to_signed,
1512                 ArchSuffix::_32,
1513             ),
1514             (false, true) => (
1515                 from_nbits == 64,
1516                 ArchSuffix::_32,
1517                 cast_unsigned_to_signed,
1518                 if from_nbits == 64 {
1519                     ArchSuffix::_64
1520                 } else {
1521                     ArchSuffix::_32
1522                 },
1523             ),
1524         };
1525     if span_truncation {
1526         span_lint(
1527             cx,
1528             CAST_POSSIBLE_TRUNCATION,
1529             expr.span,
1530             &format!(
1531                 "casting `{}` to `{}` may truncate the value{}",
1532                 cast_from,
1533                 cast_to,
1534                 match suffix_truncation {
1535                     ArchSuffix::_32 => arch_32_suffix,
1536                     ArchSuffix::_64 => arch_64_suffix,
1537                     ArchSuffix::None => "",
1538                 }
1539             ),
1540         );
1541     }
1542     if span_wrap {
1543         span_lint(
1544             cx,
1545             CAST_POSSIBLE_WRAP,
1546             expr.span,
1547             &format!(
1548                 "casting `{}` to `{}` may wrap around the value{}",
1549                 cast_from,
1550                 cast_to,
1551                 match suffix_wrap {
1552                     ArchSuffix::_32 => arch_32_suffix,
1553                     ArchSuffix::_64 => arch_64_suffix,
1554                     ArchSuffix::None => "",
1555                 }
1556             ),
1557         );
1558     }
1559 }
1560
1561 fn check_lossless(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1562     let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
1563     let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
1564     let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1565     if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned
1566     {
1567         span_lossless_lint(cx, expr, op, cast_from, cast_to);
1568     }
1569 }
1570
1571 declare_lint_pass!(Casts => [
1572     CAST_PRECISION_LOSS,
1573     CAST_SIGN_LOSS,
1574     CAST_POSSIBLE_TRUNCATION,
1575     CAST_POSSIBLE_WRAP,
1576     CAST_LOSSLESS,
1577     UNNECESSARY_CAST,
1578     CAST_PTR_ALIGNMENT,
1579     FN_TO_NUMERIC_CAST,
1580     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
1581 ]);
1582
1583 // Check if the given type is either `core::ffi::c_void` or
1584 // one of the platform specific `libc::<platform>::c_void` of libc.
1585 fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
1586     if let ty::Adt(adt, _) = ty.kind() {
1587         let names = cx.get_def_path(adt.did);
1588
1589         if names.is_empty() {
1590             return false;
1591         }
1592         if names[0] == sym::libc || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) {
1593             return true;
1594         }
1595     }
1596     false
1597 }
1598
1599 /// Returns the mantissa bits wide of a fp type.
1600 /// Will return 0 if the type is not a fp
1601 fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
1602     match typ.kind() {
1603         ty::Float(FloatTy::F32) => 23,
1604         ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
1605         _ => 0,
1606     }
1607 }
1608
1609 impl<'tcx> LateLintPass<'tcx> for Casts {
1610     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
1611         if expr.span.from_expansion() {
1612             return;
1613         }
1614         if let ExprKind::Cast(ref ex, cast_to) = expr.kind {
1615             if is_hir_ty_cfg_dependant(cx, cast_to) {
1616                 return;
1617             }
1618             let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
1619             lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
1620             if let Some(lit) = get_numeric_literal(ex) {
1621                 let literal_str = snippet_opt(cx, ex.span).unwrap_or_default();
1622
1623                 if_chain! {
1624                     if let LitKind::Int(n, _) = lit.node;
1625                     if let Some(src) = snippet_opt(cx, lit.span);
1626                     if cast_to.is_floating_point();
1627                     if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
1628                     let from_nbits = 128 - n.leading_zeros();
1629                     let to_nbits = fp_ty_mantissa_nbits(cast_to);
1630                     if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
1631                     then {
1632                         let literal_str = if is_unary_neg(ex) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
1633                         show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
1634                         return;
1635                     }
1636                 }
1637
1638                 match lit.node {
1639                     LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
1640                         show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
1641                     },
1642                     LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
1643                         show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
1644                     },
1645                     LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
1646                     _ => {
1647                         if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
1648                             span_lint(
1649                                 cx,
1650                                 UNNECESSARY_CAST,
1651                                 expr.span,
1652                                 &format!(
1653                                     "casting to the same type is unnecessary (`{}` -> `{}`)",
1654                                     cast_from, cast_to
1655                                 ),
1656                             );
1657                         }
1658                     },
1659                 }
1660             }
1661             if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
1662                 lint_numeric_casts(cx, expr, ex, cast_from, cast_to);
1663             }
1664
1665             lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
1666         } else if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind {
1667             if_chain! {
1668             if method_path.ident.name == sym!(cast);
1669             if let Some(generic_args) = method_path.args;
1670             if let [GenericArg::Type(cast_to)] = generic_args.args;
1671             // There probably is no obvious reason to do this, just to be consistent with `as` cases.
1672             if !is_hir_ty_cfg_dependant(cx, cast_to);
1673             then {
1674                 let (cast_from, cast_to) =
1675                     (cx.typeck_results().expr_ty(&args[0]), cx.typeck_results().expr_ty(expr));
1676                 lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
1677             }
1678             }
1679         }
1680     }
1681 }
1682
1683 fn is_unary_neg(expr: &Expr<'_>) -> bool {
1684     matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
1685 }
1686
1687 fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
1688     match expr.kind {
1689         ExprKind::Lit(ref lit) => Some(lit),
1690         ExprKind::Unary(UnOp::Neg, e) => {
1691             if let ExprKind::Lit(ref lit) = e.kind {
1692                 Some(lit)
1693             } else {
1694                 None
1695             }
1696         },
1697         _ => None,
1698     }
1699 }
1700
1701 fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1702     let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
1703     span_lint_and_sugg(
1704         cx,
1705         UNNECESSARY_CAST,
1706         expr.span,
1707         &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
1708         "try",
1709         format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
1710         Applicability::MachineApplicable,
1711     );
1712 }
1713
1714 fn lint_numeric_casts<'tcx>(
1715     cx: &LateContext<'tcx>,
1716     expr: &Expr<'tcx>,
1717     cast_expr: &Expr<'_>,
1718     cast_from: Ty<'tcx>,
1719     cast_to: Ty<'tcx>,
1720 ) {
1721     match (cast_from.is_integral(), cast_to.is_integral()) {
1722         (true, false) => {
1723             let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
1724             let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
1725                 32
1726             } else {
1727                 64
1728             };
1729             if is_isize_or_usize(cast_from) || from_nbits >= to_nbits {
1730                 span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64);
1731             }
1732             if from_nbits < to_nbits {
1733                 span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
1734             }
1735         },
1736         (false, true) => {
1737             span_lint(
1738                 cx,
1739                 CAST_POSSIBLE_TRUNCATION,
1740                 expr.span,
1741                 &format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to),
1742             );
1743             if !cast_to.is_signed() {
1744                 span_lint(
1745                     cx,
1746                     CAST_SIGN_LOSS,
1747                     expr.span,
1748                     &format!(
1749                         "casting `{}` to `{}` may lose the sign of the value",
1750                         cast_from, cast_to
1751                     ),
1752                 );
1753             }
1754         },
1755         (true, true) => {
1756             check_loss_of_sign(cx, expr, cast_expr, cast_from, cast_to);
1757             check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
1758             check_lossless(cx, expr, cast_expr, cast_from, cast_to);
1759         },
1760         (false, false) => {
1761             if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind(), &cast_to.kind()) {
1762                 span_lint(
1763                     cx,
1764                     CAST_POSSIBLE_TRUNCATION,
1765                     expr.span,
1766                     "casting `f64` to `f32` may truncate the value",
1767                 );
1768             }
1769             if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind(), &cast_to.kind()) {
1770                 span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
1771             }
1772         },
1773     }
1774 }
1775
1776 fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
1777     if_chain! {
1778         if let ty::RawPtr(from_ptr_ty) = &cast_from.kind();
1779         if let ty::RawPtr(to_ptr_ty) = &cast_to.kind();
1780         if let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty);
1781         if let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty);
1782         if from_layout.align.abi < to_layout.align.abi;
1783         // with c_void, we inherently need to trust the user
1784         if !is_c_void(cx, from_ptr_ty.ty);
1785         // when casting from a ZST, we don't know enough to properly lint
1786         if !from_layout.is_zst();
1787         then {
1788             span_lint(
1789                 cx,
1790                 CAST_PTR_ALIGNMENT,
1791                 expr.span,
1792                 &format!(
1793                     "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)",
1794                     cast_from,
1795                     cast_to,
1796                     from_layout.align.abi.bytes(),
1797                     to_layout.align.abi.bytes(),
1798                 ),
1799             );
1800         }
1801     }
1802 }
1803
1804 fn lint_fn_to_numeric_cast(
1805     cx: &LateContext<'_>,
1806     expr: &Expr<'_>,
1807     cast_expr: &Expr<'_>,
1808     cast_from: Ty<'_>,
1809     cast_to: Ty<'_>,
1810 ) {
1811     // We only want to check casts to `ty::Uint` or `ty::Int`
1812     match cast_to.kind() {
1813         ty::Uint(_) | ty::Int(..) => { /* continue on */ },
1814         _ => return,
1815     }
1816     match cast_from.kind() {
1817         ty::FnDef(..) | ty::FnPtr(_) => {
1818             let mut applicability = Applicability::MaybeIncorrect;
1819             let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
1820
1821             let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1822             if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
1823                 span_lint_and_sugg(
1824                     cx,
1825                     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
1826                     expr.span,
1827                     &format!(
1828                         "casting function pointer `{}` to `{}`, which truncates the value",
1829                         from_snippet, cast_to
1830                     ),
1831                     "try",
1832                     format!("{} as usize", from_snippet),
1833                     applicability,
1834                 );
1835             } else if *cast_to.kind() != ty::Uint(UintTy::Usize) {
1836                 span_lint_and_sugg(
1837                     cx,
1838                     FN_TO_NUMERIC_CAST,
1839                     expr.span,
1840                     &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
1841                     "try",
1842                     format!("{} as usize", from_snippet),
1843                     applicability,
1844                 );
1845             }
1846         },
1847         _ => {},
1848     }
1849 }
1850
1851 declare_clippy_lint! {
1852     /// **What it does:** Checks for types used in structs, parameters and `let`
1853     /// declarations above a certain complexity threshold.
1854     ///
1855     /// **Why is this bad?** Too complex types make the code less readable. Consider
1856     /// using a `type` definition to simplify them.
1857     ///
1858     /// **Known problems:** None.
1859     ///
1860     /// **Example:**
1861     /// ```rust
1862     /// # use std::rc::Rc;
1863     /// struct Foo {
1864     ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
1865     /// }
1866     /// ```
1867     pub TYPE_COMPLEXITY,
1868     complexity,
1869     "usage of very complex types that might be better factored into `type` definitions"
1870 }
1871
1872 pub struct TypeComplexity {
1873     threshold: u64,
1874 }
1875
1876 impl TypeComplexity {
1877     #[must_use]
1878     pub fn new(threshold: u64) -> Self {
1879         Self { threshold }
1880     }
1881 }
1882
1883 impl_lint_pass!(TypeComplexity => [TYPE_COMPLEXITY]);
1884
1885 impl<'tcx> LateLintPass<'tcx> for TypeComplexity {
1886     fn check_fn(
1887         &mut self,
1888         cx: &LateContext<'tcx>,
1889         _: FnKind<'tcx>,
1890         decl: &'tcx FnDecl<'_>,
1891         _: &'tcx Body<'_>,
1892         _: Span,
1893         _: HirId,
1894     ) {
1895         self.check_fndecl(cx, decl);
1896     }
1897
1898     fn check_struct_field(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::StructField<'_>) {
1899         // enum variants are also struct fields now
1900         self.check_type(cx, &field.ty);
1901     }
1902
1903     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
1904         match item.kind {
1905             ItemKind::Static(ref ty, _, _) | ItemKind::Const(ref ty, _) => self.check_type(cx, ty),
1906             // functions, enums, structs, impls and traits are covered
1907             _ => (),
1908         }
1909     }
1910
1911     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
1912         match item.kind {
1913             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty),
1914             TraitItemKind::Fn(FnSig { ref decl, .. }, TraitFn::Required(_)) => self.check_fndecl(cx, decl),
1915             // methods with default impl are covered by check_fn
1916             _ => (),
1917         }
1918     }
1919
1920     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
1921         match item.kind {
1922             ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_type(cx, ty),
1923             // methods are covered by check_fn
1924             _ => (),
1925         }
1926     }
1927
1928     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
1929         if let Some(ref ty) = local.ty {
1930             self.check_type(cx, ty);
1931         }
1932     }
1933 }
1934
1935 impl<'tcx> TypeComplexity {
1936     fn check_fndecl(&self, cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>) {
1937         for arg in decl.inputs {
1938             self.check_type(cx, arg);
1939         }
1940         if let FnRetTy::Return(ref ty) = decl.output {
1941             self.check_type(cx, ty);
1942         }
1943     }
1944
1945     fn check_type(&self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
1946         if ty.span.from_expansion() {
1947             return;
1948         }
1949         let score = {
1950             let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
1951             visitor.visit_ty(ty);
1952             visitor.score
1953         };
1954
1955         if score > self.threshold {
1956             span_lint(
1957                 cx,
1958                 TYPE_COMPLEXITY,
1959                 ty.span,
1960                 "very complex type used. Consider factoring parts into `type` definitions",
1961             );
1962         }
1963     }
1964 }
1965
1966 /// Walks a type and assigns a complexity score to it.
1967 struct TypeComplexityVisitor {
1968     /// total complexity score of the type
1969     score: u64,
1970     /// current nesting level
1971     nest: u64,
1972 }
1973
1974 impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
1975     type Map = Map<'tcx>;
1976
1977     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
1978         let (add_score, sub_nest) = match ty.kind {
1979             // _, &x and *x have only small overhead; don't mess with nesting level
1980             TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
1981
1982             // the "normal" components of a type: named types, arrays/tuples
1983             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
1984
1985             // function types bring a lot of overhead
1986             TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
1987
1988             TyKind::TraitObject(ref param_bounds, _) => {
1989                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
1990                     bound
1991                         .bound_generic_params
1992                         .iter()
1993                         .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
1994                 });
1995                 if has_lifetime_parameters {
1996                     // complex trait bounds like A<'a, 'b>
1997                     (50 * self.nest, 1)
1998                 } else {
1999                     // simple trait bounds like A + B
2000                     (20 * self.nest, 0)
2001                 }
2002             },
2003
2004             _ => (0, 0),
2005         };
2006         self.score += add_score;
2007         self.nest += sub_nest;
2008         walk_ty(self, ty);
2009         self.nest -= sub_nest;
2010     }
2011     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
2012         NestedVisitorMap::None
2013     }
2014 }
2015
2016 declare_clippy_lint! {
2017     /// **What it does:** Checks for expressions where a character literal is cast
2018     /// to `u8` and suggests using a byte literal instead.
2019     ///
2020     /// **Why is this bad?** In general, casting values to smaller types is
2021     /// error-prone and should be avoided where possible. In the particular case of
2022     /// converting a character literal to u8, it is easy to avoid by just using a
2023     /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
2024     /// than `'a' as u8`.
2025     ///
2026     /// **Known problems:** None.
2027     ///
2028     /// **Example:**
2029     /// ```rust,ignore
2030     /// 'x' as u8
2031     /// ```
2032     ///
2033     /// A better version, using the byte literal:
2034     ///
2035     /// ```rust,ignore
2036     /// b'x'
2037     /// ```
2038     pub CHAR_LIT_AS_U8,
2039     complexity,
2040     "casting a character literal to `u8` truncates"
2041 }
2042
2043 declare_lint_pass!(CharLitAsU8 => [CHAR_LIT_AS_U8]);
2044
2045 impl<'tcx> LateLintPass<'tcx> for CharLitAsU8 {
2046     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
2047         if_chain! {
2048             if !expr.span.from_expansion();
2049             if let ExprKind::Cast(e, _) = &expr.kind;
2050             if let ExprKind::Lit(l) = &e.kind;
2051             if let LitKind::Char(c) = l.node;
2052             if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind();
2053             then {
2054                 let mut applicability = Applicability::MachineApplicable;
2055                 let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
2056
2057                 span_lint_and_then(
2058                     cx,
2059                     CHAR_LIT_AS_U8,
2060                     expr.span,
2061                     "casting a character literal to `u8` truncates",
2062                     |diag| {
2063                         diag.note("`char` is four bytes wide, but `u8` is a single byte");
2064
2065                         if c.is_ascii() {
2066                             diag.span_suggestion(
2067                                 expr.span,
2068                                 "use a byte literal instead",
2069                                 format!("b{}", snippet),
2070                                 applicability,
2071                             );
2072                         }
2073                 });
2074             }
2075         }
2076     }
2077 }
2078
2079 declare_clippy_lint! {
2080     /// **What it does:** Checks for comparisons where one side of the relation is
2081     /// either the minimum or maximum value for its type and warns if it involves a
2082     /// case that is always true or always false. Only integer and boolean types are
2083     /// checked.
2084     ///
2085     /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
2086     /// that it is possible for `x` to be less than the minimum. Expressions like
2087     /// `max < x` are probably mistakes.
2088     ///
2089     /// **Known problems:** For `usize` the size of the current compile target will
2090     /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
2091     /// a comparison to detect target pointer width will trigger this lint. One can
2092     /// use `mem::sizeof` and compare its value or conditional compilation
2093     /// attributes
2094     /// like `#[cfg(target_pointer_width = "64")] ..` instead.
2095     ///
2096     /// **Example:**
2097     ///
2098     /// ```rust
2099     /// let vec: Vec<isize> = Vec::new();
2100     /// if vec.len() <= 0 {}
2101     /// if 100 > i32::MAX {}
2102     /// ```
2103     pub ABSURD_EXTREME_COMPARISONS,
2104     correctness,
2105     "a comparison with a maximum or minimum value that is always true or false"
2106 }
2107
2108 declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
2109
2110 enum ExtremeType {
2111     Minimum,
2112     Maximum,
2113 }
2114
2115 struct ExtremeExpr<'a> {
2116     which: ExtremeType,
2117     expr: &'a Expr<'a>,
2118 }
2119
2120 enum AbsurdComparisonResult {
2121     AlwaysFalse,
2122     AlwaysTrue,
2123     InequalityImpossible,
2124 }
2125
2126 fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
2127     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
2128         let precast_ty = cx.typeck_results().expr_ty(cast_exp);
2129         let cast_ty = cx.typeck_results().expr_ty(expr);
2130
2131         return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
2132     }
2133
2134     false
2135 }
2136
2137 fn detect_absurd_comparison<'tcx>(
2138     cx: &LateContext<'tcx>,
2139     op: BinOpKind,
2140     lhs: &'tcx Expr<'_>,
2141     rhs: &'tcx Expr<'_>,
2142 ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
2143     use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
2144     use crate::types::ExtremeType::{Maximum, Minimum};
2145     use crate::utils::comparisons::{normalize_comparison, Rel};
2146
2147     // absurd comparison only makes sense on primitive types
2148     // primitive types don't implement comparison operators with each other
2149     if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
2150         return None;
2151     }
2152
2153     // comparisons between fix sized types and target sized types are considered unanalyzable
2154     if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
2155         return None;
2156     }
2157
2158     let (rel, normalized_lhs, normalized_rhs) = normalize_comparison(op, lhs, rhs)?;
2159
2160     let lx = detect_extreme_expr(cx, normalized_lhs);
2161     let rx = detect_extreme_expr(cx, normalized_rhs);
2162
2163     Some(match rel {
2164         Rel::Lt => {
2165             match (lx, rx) {
2166                 (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
2167                 (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
2168                 _ => return None,
2169             }
2170         },
2171         Rel::Le => {
2172             match (lx, rx) {
2173                 (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
2174                 (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
2175                 (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
2176                 (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
2177                 _ => return None,
2178             }
2179         },
2180         Rel::Ne | Rel::Eq => return None,
2181     })
2182 }
2183
2184 fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
2185     use crate::types::ExtremeType::{Maximum, Minimum};
2186
2187     let ty = cx.typeck_results().expr_ty(expr);
2188
2189     let cv = constant(cx, cx.typeck_results(), expr)?.0;
2190
2191     let which = match (ty.kind(), cv) {
2192         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
2193         (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
2194             Minimum
2195         },
2196
2197         (&ty::Bool, Constant::Bool(true)) => Maximum,
2198         (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
2199             Maximum
2200         },
2201         (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
2202
2203         _ => return None,
2204     };
2205     Some(ExtremeExpr { which, expr })
2206 }
2207
2208 impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons {
2209     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
2210         use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
2211         use crate::types::ExtremeType::{Maximum, Minimum};
2212
2213         if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
2214             if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
2215                 if !expr.span.from_expansion() {
2216                     let msg = "this comparison involving the minimum or maximum element for this \
2217                                type contains a case that is always true or always false";
2218
2219                     let conclusion = match result {
2220                         AlwaysFalse => "this comparison is always false".to_owned(),
2221                         AlwaysTrue => "this comparison is always true".to_owned(),
2222                         InequalityImpossible => format!(
2223                             "the case where the two sides are not equal never occurs, consider using `{} == {}` \
2224                              instead",
2225                             snippet(cx, lhs.span, "lhs"),
2226                             snippet(cx, rhs.span, "rhs")
2227                         ),
2228                     };
2229
2230                     let help = format!(
2231                         "because `{}` is the {} value for this type, {}",
2232                         snippet(cx, culprit.expr.span, "x"),
2233                         match culprit.which {
2234                             Minimum => "minimum",
2235                             Maximum => "maximum",
2236                         },
2237                         conclusion
2238                     );
2239
2240                     span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
2241                 }
2242             }
2243         }
2244     }
2245 }
2246
2247 declare_clippy_lint! {
2248     /// **What it does:** Checks for comparisons where the relation is always either
2249     /// true or false, but where one side has been upcast so that the comparison is
2250     /// necessary. Only integer types are checked.
2251     ///
2252     /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
2253     /// will mistakenly imply that it is possible for `x` to be outside the range of
2254     /// `u8`.
2255     ///
2256     /// **Known problems:**
2257     /// https://github.com/rust-lang/rust-clippy/issues/886
2258     ///
2259     /// **Example:**
2260     /// ```rust
2261     /// let x: u8 = 1;
2262     /// (x as u32) > 300;
2263     /// ```
2264     pub INVALID_UPCAST_COMPARISONS,
2265     pedantic,
2266     "a comparison involving an upcast which is always true or false"
2267 }
2268
2269 declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
2270
2271 #[derive(Copy, Clone, Debug, Eq)]
2272 enum FullInt {
2273     S(i128),
2274     U(u128),
2275 }
2276
2277 impl FullInt {
2278     #[allow(clippy::cast_sign_loss)]
2279     #[must_use]
2280     fn cmp_s_u(s: i128, u: u128) -> Ordering {
2281         if s < 0 {
2282             Ordering::Less
2283         } else if u > (i128::MAX as u128) {
2284             Ordering::Greater
2285         } else {
2286             (s as u128).cmp(&u)
2287         }
2288     }
2289 }
2290
2291 impl PartialEq for FullInt {
2292     #[must_use]
2293     fn eq(&self, other: &Self) -> bool {
2294         self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
2295     }
2296 }
2297
2298 impl PartialOrd for FullInt {
2299     #[must_use]
2300     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2301         Some(match (self, other) {
2302             (&Self::S(s), &Self::S(o)) => s.cmp(&o),
2303             (&Self::U(s), &Self::U(o)) => s.cmp(&o),
2304             (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
2305             (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
2306         })
2307     }
2308 }
2309
2310 impl Ord for FullInt {
2311     #[must_use]
2312     fn cmp(&self, other: &Self) -> Ordering {
2313         self.partial_cmp(other)
2314             .expect("`partial_cmp` for FullInt can never return `None`")
2315     }
2316 }
2317
2318 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
2319     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
2320         let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
2321         let cast_ty = cx.typeck_results().expr_ty(expr);
2322         // if it's a cast from i32 to u32 wrapping will invalidate all these checks
2323         if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
2324             return None;
2325         }
2326         match pre_cast_ty.kind() {
2327             ty::Int(int_ty) => Some(match int_ty {
2328                 IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
2329                 IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
2330                 IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
2331                 IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
2332                 IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
2333                 IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
2334             }),
2335             ty::Uint(uint_ty) => Some(match uint_ty {
2336                 UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
2337                 UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
2338                 UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
2339                 UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
2340                 UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
2341                 UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
2342             }),
2343             _ => None,
2344         }
2345     } else {
2346         None
2347     }
2348 }
2349
2350 fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
2351     let val = constant(cx, cx.typeck_results(), expr)?.0;
2352     if let Constant::Int(const_int) = val {
2353         match *cx.typeck_results().expr_ty(expr).kind() {
2354             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
2355             ty::Uint(_) => Some(FullInt::U(const_int)),
2356             _ => None,
2357         }
2358     } else {
2359         None
2360     }
2361 }
2362
2363 fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
2364     if let ExprKind::Cast(ref cast_val, _) = expr.kind {
2365         span_lint(
2366             cx,
2367             INVALID_UPCAST_COMPARISONS,
2368             span,
2369             &format!(
2370                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
2371                 snippet(cx, cast_val.span, "the expression"),
2372                 if always { "true" } else { "false" },
2373             ),
2374         );
2375     }
2376 }
2377
2378 fn upcast_comparison_bounds_err<'tcx>(
2379     cx: &LateContext<'tcx>,
2380     span: Span,
2381     rel: comparisons::Rel,
2382     lhs_bounds: Option<(FullInt, FullInt)>,
2383     lhs: &'tcx Expr<'_>,
2384     rhs: &'tcx Expr<'_>,
2385     invert: bool,
2386 ) {
2387     use crate::utils::comparisons::Rel;
2388
2389     if let Some((lb, ub)) = lhs_bounds {
2390         if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
2391             if rel == Rel::Eq || rel == Rel::Ne {
2392                 if norm_rhs_val < lb || norm_rhs_val > ub {
2393                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
2394                 }
2395             } else if match rel {
2396                 Rel::Lt => {
2397                     if invert {
2398                         norm_rhs_val < lb
2399                     } else {
2400                         ub < norm_rhs_val
2401                     }
2402                 },
2403                 Rel::Le => {
2404                     if invert {
2405                         norm_rhs_val <= lb
2406                     } else {
2407                         ub <= norm_rhs_val
2408                     }
2409                 },
2410                 Rel::Eq | Rel::Ne => unreachable!(),
2411             } {
2412                 err_upcast_comparison(cx, span, lhs, true)
2413             } else if match rel {
2414                 Rel::Lt => {
2415                     if invert {
2416                         norm_rhs_val >= ub
2417                     } else {
2418                         lb >= norm_rhs_val
2419                     }
2420                 },
2421                 Rel::Le => {
2422                     if invert {
2423                         norm_rhs_val > ub
2424                     } else {
2425                         lb > norm_rhs_val
2426                     }
2427                 },
2428                 Rel::Eq | Rel::Ne => unreachable!(),
2429             } {
2430                 err_upcast_comparison(cx, span, lhs, false)
2431             }
2432         }
2433     }
2434 }
2435
2436 impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
2437     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
2438         if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
2439             let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
2440             let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
2441                 val
2442             } else {
2443                 return;
2444             };
2445
2446             let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
2447             let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
2448
2449             upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
2450             upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
2451         }
2452     }
2453 }
2454
2455 declare_clippy_lint! {
2456     /// **What it does:** Checks for public `impl` or `fn` missing generalization
2457     /// over different hashers and implicitly defaulting to the default hashing
2458     /// algorithm (`SipHash`).
2459     ///
2460     /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
2461     /// used with them.
2462     ///
2463     /// **Known problems:** Suggestions for replacing constructors can contain
2464     /// false-positives. Also applying suggestions can require modification of other
2465     /// pieces of code, possibly including external crates.
2466     ///
2467     /// **Example:**
2468     /// ```rust
2469     /// # use std::collections::HashMap;
2470     /// # use std::hash::{Hash, BuildHasher};
2471     /// # trait Serialize {};
2472     /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
2473     ///
2474     /// pub fn foo(map: &mut HashMap<i32, i32>) { }
2475     /// ```
2476     /// could be rewritten as
2477     /// ```rust
2478     /// # use std::collections::HashMap;
2479     /// # use std::hash::{Hash, BuildHasher};
2480     /// # trait Serialize {};
2481     /// impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
2482     ///
2483     /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
2484     /// ```
2485     pub IMPLICIT_HASHER,
2486     pedantic,
2487     "missing generalization over different hashers"
2488 }
2489
2490 declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
2491
2492 impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
2493     #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
2494     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
2495         use rustc_span::BytePos;
2496
2497         fn suggestion<'tcx>(
2498             cx: &LateContext<'tcx>,
2499             diag: &mut DiagnosticBuilder<'_>,
2500             generics_span: Span,
2501             generics_suggestion_span: Span,
2502             target: &ImplicitHasherType<'_>,
2503             vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
2504         ) {
2505             let generics_snip = snippet(cx, generics_span, "");
2506             // trim `<` `>`
2507             let generics_snip = if generics_snip.is_empty() {
2508                 ""
2509             } else {
2510                 &generics_snip[1..generics_snip.len() - 1]
2511             };
2512
2513             multispan_sugg(
2514                 diag,
2515                 "consider adding a type parameter",
2516                 vec![
2517                     (
2518                         generics_suggestion_span,
2519                         format!(
2520                             "<{}{}S: ::std::hash::BuildHasher{}>",
2521                             generics_snip,
2522                             if generics_snip.is_empty() { "" } else { ", " },
2523                             if vis.suggestions.is_empty() {
2524                                 ""
2525                             } else {
2526                                 // request users to add `Default` bound so that generic constructors can be used
2527                                 " + Default"
2528                             },
2529                         ),
2530                     ),
2531                     (
2532                         target.span(),
2533                         format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
2534                     ),
2535                 ],
2536             );
2537
2538             if !vis.suggestions.is_empty() {
2539                 multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
2540             }
2541         }
2542
2543         if !cx.access_levels.is_exported(item.hir_id()) {
2544             return;
2545         }
2546
2547         match item.kind {
2548             ItemKind::Impl(ref impl_) => {
2549                 let mut vis = ImplicitHasherTypeVisitor::new(cx);
2550                 vis.visit_ty(impl_.self_ty);
2551
2552                 for target in &vis.found {
2553                     if differing_macro_contexts(item.span, target.span()) {
2554                         return;
2555                     }
2556
2557                     let generics_suggestion_span = impl_.generics.span.substitute_dummy({
2558                         let pos = snippet_opt(cx, item.span.until(target.span()))
2559                             .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
2560                         if let Some(pos) = pos {
2561                             Span::new(pos, pos, item.span.data().ctxt)
2562                         } else {
2563                             return;
2564                         }
2565                     });
2566
2567                     let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
2568                     for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
2569                         ctr_vis.visit_impl_item(item);
2570                     }
2571
2572                     span_lint_and_then(
2573                         cx,
2574                         IMPLICIT_HASHER,
2575                         target.span(),
2576                         &format!(
2577                             "impl for `{}` should be generalized over different hashers",
2578                             target.type_name()
2579                         ),
2580                         move |diag| {
2581                             suggestion(cx, diag, impl_.generics.span, generics_suggestion_span, target, ctr_vis);
2582                         },
2583                     );
2584                 }
2585             },
2586             ItemKind::Fn(ref sig, ref generics, body_id) => {
2587                 let body = cx.tcx.hir().body(body_id);
2588
2589                 for ty in sig.decl.inputs {
2590                     let mut vis = ImplicitHasherTypeVisitor::new(cx);
2591                     vis.visit_ty(ty);
2592
2593                     for target in &vis.found {
2594                         if in_external_macro(cx.sess(), generics.span) {
2595                             continue;
2596                         }
2597                         let generics_suggestion_span = generics.span.substitute_dummy({
2598                             let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
2599                                 .and_then(|snip| {
2600                                     let i = snip.find("fn")?;
2601                                     Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
2602                                 })
2603                                 .expect("failed to create span for type parameters");
2604                             Span::new(pos, pos, item.span.data().ctxt)
2605                         });
2606
2607                         let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
2608                         ctr_vis.visit_body(body);
2609
2610                         span_lint_and_then(
2611                             cx,
2612                             IMPLICIT_HASHER,
2613                             target.span(),
2614                             &format!(
2615                                 "parameter of type `{}` should be generalized over different hashers",
2616                                 target.type_name()
2617                             ),
2618                             move |diag| {
2619                                 suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
2620                             },
2621                         );
2622                     }
2623                 }
2624             },
2625             _ => {},
2626         }
2627     }
2628 }
2629
2630 enum ImplicitHasherType<'tcx> {
2631     HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
2632     HashSet(Span, Ty<'tcx>, Cow<'static, str>),
2633 }
2634
2635 impl<'tcx> ImplicitHasherType<'tcx> {
2636     /// Checks that `ty` is a target type without a `BuildHasher`.
2637     fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
2638         if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.kind {
2639             let params: Vec<_> = path
2640                 .segments
2641                 .last()
2642                 .as_ref()?
2643                 .args
2644                 .as_ref()?
2645                 .args
2646                 .iter()
2647                 .filter_map(|arg| match arg {
2648                     GenericArg::Type(ty) => Some(ty),
2649                     _ => None,
2650                 })
2651                 .collect();
2652             let params_len = params.len();
2653
2654             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
2655
2656             if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) && params_len == 2 {
2657                 Some(ImplicitHasherType::HashMap(
2658                     hir_ty.span,
2659                     ty,
2660                     snippet(cx, params[0].span, "K"),
2661                     snippet(cx, params[1].span, "V"),
2662                 ))
2663             } else if is_type_diagnostic_item(cx, ty, sym!(hashset_type)) && params_len == 1 {
2664                 Some(ImplicitHasherType::HashSet(
2665                     hir_ty.span,
2666                     ty,
2667                     snippet(cx, params[0].span, "T"),
2668                 ))
2669             } else {
2670                 None
2671             }
2672         } else {
2673             None
2674         }
2675     }
2676
2677     fn type_name(&self) -> &'static str {
2678         match *self {
2679             ImplicitHasherType::HashMap(..) => "HashMap",
2680             ImplicitHasherType::HashSet(..) => "HashSet",
2681         }
2682     }
2683
2684     fn type_arguments(&self) -> String {
2685         match *self {
2686             ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
2687             ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
2688         }
2689     }
2690
2691     fn ty(&self) -> Ty<'tcx> {
2692         match *self {
2693             ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
2694         }
2695     }
2696
2697     fn span(&self) -> Span {
2698         match *self {
2699             ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
2700         }
2701     }
2702 }
2703
2704 struct ImplicitHasherTypeVisitor<'a, 'tcx> {
2705     cx: &'a LateContext<'tcx>,
2706     found: Vec<ImplicitHasherType<'tcx>>,
2707 }
2708
2709 impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
2710     fn new(cx: &'a LateContext<'tcx>) -> Self {
2711         Self { cx, found: vec![] }
2712     }
2713 }
2714
2715 impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
2716     type Map = Map<'tcx>;
2717
2718     fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
2719         if let Some(target) = ImplicitHasherType::new(self.cx, t) {
2720             self.found.push(target);
2721         }
2722
2723         walk_ty(self, t);
2724     }
2725
2726     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
2727         NestedVisitorMap::None
2728     }
2729 }
2730
2731 /// Looks for default-hasher-dependent constructors like `HashMap::new`.
2732 struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
2733     cx: &'a LateContext<'tcx>,
2734     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
2735     target: &'b ImplicitHasherType<'tcx>,
2736     suggestions: BTreeMap<Span, String>,
2737 }
2738
2739 impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
2740     fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
2741         Self {
2742             cx,
2743             maybe_typeck_results: cx.maybe_typeck_results(),
2744             target,
2745             suggestions: BTreeMap::new(),
2746         }
2747     }
2748 }
2749
2750 impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
2751     type Map = Map<'tcx>;
2752
2753     fn visit_body(&mut self, body: &'tcx Body<'_>) {
2754         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
2755         walk_body(self, body);
2756         self.maybe_typeck_results = old_maybe_typeck_results;
2757     }
2758
2759     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
2760         if_chain! {
2761             if let ExprKind::Call(ref fun, ref args) = e.kind;
2762             if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
2763             if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
2764             then {
2765                 if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
2766                     return;
2767                 }
2768
2769                 if match_path(ty_path, &paths::HASHMAP) {
2770                     if method.ident.name == sym::new {
2771                         self.suggestions
2772                             .insert(e.span, "HashMap::default()".to_string());
2773                     } else if method.ident.name == sym!(with_capacity) {
2774                         self.suggestions.insert(
2775                             e.span,
2776                             format!(
2777                                 "HashMap::with_capacity_and_hasher({}, Default::default())",
2778                                 snippet(self.cx, args[0].span, "capacity"),
2779                             ),
2780                         );
2781                     }
2782                 } else if match_path(ty_path, &paths::HASHSET) {
2783                     if method.ident.name == sym::new {
2784                         self.suggestions
2785                             .insert(e.span, "HashSet::default()".to_string());
2786                     } else if method.ident.name == sym!(with_capacity) {
2787                         self.suggestions.insert(
2788                             e.span,
2789                             format!(
2790                                 "HashSet::with_capacity_and_hasher({}, Default::default())",
2791                                 snippet(self.cx, args[0].span, "capacity"),
2792                             ),
2793                         );
2794                     }
2795                 }
2796             }
2797         }
2798
2799         walk_expr(self, e);
2800     }
2801
2802     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
2803         NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
2804     }
2805 }
2806
2807 declare_clippy_lint! {
2808     /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
2809     ///
2810     /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
2811     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
2812     /// mutable.
2813     ///
2814     /// **Known problems:** None.
2815     ///
2816     /// **Example:**
2817     /// ```rust,ignore
2818     /// fn x(r: &i32) {
2819     ///     unsafe {
2820     ///         *(r as *const _ as *mut _) += 1;
2821     ///     }
2822     /// }
2823     /// ```
2824     ///
2825     /// Instead consider using interior mutability types.
2826     ///
2827     /// ```rust
2828     /// use std::cell::UnsafeCell;
2829     ///
2830     /// fn x(r: &UnsafeCell<i32>) {
2831     ///     unsafe {
2832     ///         *r.get() += 1;
2833     ///     }
2834     /// }
2835     /// ```
2836     pub CAST_REF_TO_MUT,
2837     correctness,
2838     "a cast of reference to a mutable pointer"
2839 }
2840
2841 declare_lint_pass!(RefToMut => [CAST_REF_TO_MUT]);
2842
2843 impl<'tcx> LateLintPass<'tcx> for RefToMut {
2844     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
2845         if_chain! {
2846             if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind;
2847             if let ExprKind::Cast(e, t) = &e.kind;
2848             if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
2849             if let ExprKind::Cast(e, t) = &e.kind;
2850             if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind;
2851             if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind();
2852             then {
2853                 span_lint(
2854                     cx,
2855                     CAST_REF_TO_MUT,
2856                     expr.span,
2857                     "casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell`",
2858                 );
2859             }
2860         }
2861     }
2862 }
2863
2864 const PTR_AS_PTR_MSRV: RustcVersion = RustcVersion::new(1, 38, 0);
2865
2866 declare_clippy_lint! {
2867     /// **What it does:**
2868     /// Checks for `as` casts between raw pointers without changing its mutability,
2869     /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
2870     ///
2871     /// **Why is this bad?**
2872     /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
2873     /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
2874     ///
2875     /// **Known problems:** None.
2876     ///
2877     /// **Example:**
2878     ///
2879     /// ```rust
2880     /// let ptr: *const u32 = &42_u32;
2881     /// let mut_ptr: *mut u32 = &mut 42_u32;
2882     /// let _ = ptr as *const i32;
2883     /// let _ = mut_ptr as *mut i32;
2884     /// ```
2885     /// Use instead:
2886     /// ```rust
2887     /// let ptr: *const u32 = &42_u32;
2888     /// let mut_ptr: *mut u32 = &mut 42_u32;
2889     /// let _ = ptr.cast::<i32>();
2890     /// let _ = mut_ptr.cast::<i32>();
2891     /// ```
2892     pub PTR_AS_PTR,
2893     pedantic,
2894     "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
2895 }
2896
2897 pub struct PtrAsPtr {
2898     msrv: Option<RustcVersion>,
2899 }
2900
2901 impl PtrAsPtr {
2902     #[must_use]
2903     pub fn new(msrv: Option<RustcVersion>) -> Self {
2904         Self { msrv }
2905     }
2906 }
2907
2908 impl_lint_pass!(PtrAsPtr => [PTR_AS_PTR]);
2909
2910 impl<'tcx> LateLintPass<'tcx> for PtrAsPtr {
2911     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
2912         if !meets_msrv(self.msrv.as_ref(), &PTR_AS_PTR_MSRV) {
2913             return;
2914         }
2915
2916         if expr.span.from_expansion() {
2917             return;
2918         }
2919
2920         if_chain! {
2921             if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind;
2922             let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr));
2923             if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
2924             if let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind();
2925             if matches!((from_mutbl, to_mutbl),
2926                 (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
2927             // The `U` in `pointer::cast` have to be `Sized`
2928             // as explained here: https://github.com/rust-lang/rust/issues/60602.
2929             if to_pointee_ty.is_sized(cx.tcx.at(expr.span), cx.param_env);
2930             then {
2931                 let mut applicability = Applicability::MachineApplicable;
2932                 let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
2933                 let turbofish = match &cast_to_hir_ty.kind {
2934                         TyKind::Infer => Cow::Borrowed(""),
2935                         TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
2936                         _ => Cow::Owned(format!("::<{}>", to_pointee_ty)),
2937                     };
2938                 span_lint_and_sugg(
2939                     cx,
2940                     PTR_AS_PTR,
2941                     expr.span,
2942                     "`as` casting between raw pointers without changing its mutability",
2943                     "try `pointer::cast`, a safer alternative",
2944                     format!("{}.cast{}()", cast_expr_sugg.maybe_par(), turbofish),
2945                     applicability,
2946                 );
2947             }
2948         }
2949     }
2950
2951     extract_msrv_attr!(LateContext);
2952 }