]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/types.rs
Auto merge of #4308 - jakubadamw:use-self-variant-scope, r=flip1995
[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::hir;
9 use rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
10 use rustc::hir::*;
11 use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
12 use rustc::ty::layout::LayoutOf;
13 use rustc::ty::{self, InferTy, Ty, TyCtxt, TypeckTables};
14 use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
15 use rustc_errors::Applicability;
16 use rustc_target::spec::abi::Abi;
17 use rustc_typeck::hir_ty_to_ty;
18 use syntax::ast::{FloatTy, IntTy, UintTy};
19 use syntax::errors::DiagnosticBuilder;
20 use syntax::source_map::Span;
21 use syntax::symbol::sym;
22
23 use crate::consts::{constant, Constant};
24 use crate::utils::paths;
25 use crate::utils::{
26     clip, comparisons, differing_macro_contexts, higher, in_constant, in_macro_or_desugar, int_bits, last_path_segment,
27     match_def_path, match_path, multispan_sugg, same_tys, sext, snippet, snippet_opt, snippet_with_applicability,
28     span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, unsext,
29 };
30
31 declare_clippy_lint! {
32     /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
33     ///
34     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
35     /// the heap. So if you `Box` it, you just add another level of indirection
36     /// without any benefit whatsoever.
37     ///
38     /// **Known problems:** None.
39     ///
40     /// **Example:**
41     /// ```rust,ignore
42     /// struct X {
43     ///     values: Box<Vec<Foo>>,
44     /// }
45     /// ```
46     ///
47     /// Better:
48     ///
49     /// ```rust,ignore
50     /// struct X {
51     ///     values: Vec<Foo>,
52     /// }
53     /// ```
54     pub BOX_VEC,
55     perf,
56     "usage of `Box<Vec<T>>`, vector elements are already on the heap"
57 }
58
59 declare_clippy_lint! {
60     /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
61     ///
62     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
63     /// the heap. So if you `Box` its contents, you just add another level of indirection.
64     ///
65     /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see #3530,
66     /// 1st comment).
67     ///
68     /// **Example:**
69     /// ```rust
70     /// struct X {
71     ///     values: Vec<Box<i32>>,
72     /// }
73     /// ```
74     ///
75     /// Better:
76     ///
77     /// ```rust
78     /// struct X {
79     ///     values: Vec<i32>,
80     /// }
81     /// ```
82     pub VEC_BOX,
83     complexity,
84     "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
85 }
86
87 declare_clippy_lint! {
88     /// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
89     /// definitions
90     ///
91     /// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
92     /// represents an optional optional value which is logically the same thing as an optional
93     /// value but has an unneeded extra level of wrapping.
94     ///
95     /// **Known problems:** None.
96     ///
97     /// **Example**
98     /// ```rust
99     /// fn x() -> Option<Option<u32>> {
100     ///     None
101     /// }
102     /// ```
103     pub OPTION_OPTION,
104     complexity,
105     "usage of `Option<Option<T>>`"
106 }
107
108 declare_clippy_lint! {
109     /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
110     /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
111     ///
112     /// **Why is this bad?** Gankro says:
113     ///
114     /// > The TL;DR of `LinkedList` is that it's built on a massive amount of
115     /// pointers and indirection.
116     /// > It wastes memory, it has terrible cache locality, and is all-around slow.
117     /// `RingBuf`, while
118     /// > "only" amortized for push/pop, should be faster in the general case for
119     /// almost every possible
120     /// > workload, and isn't even amortized at all if you can predict the capacity
121     /// you need.
122     /// >
123     /// > `LinkedList`s are only really good if you're doing a lot of merging or
124     /// splitting of lists.
125     /// > This is because they can just mangle some pointers instead of actually
126     /// copying the data. Even
127     /// > if you're doing a lot of insertion in the middle of the list, `RingBuf`
128     /// can still be better
129     /// > because of how expensive it is to seek to the middle of a `LinkedList`.
130     ///
131     /// **Known problems:** False positives – the instances where using a
132     /// `LinkedList` makes sense are few and far between, but they can still happen.
133     ///
134     /// **Example:**
135     /// ```rust
136     /// let x = LinkedList::new();
137     /// ```
138     pub LINKEDLIST,
139     pedantic,
140     "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque"
141 }
142
143 declare_clippy_lint! {
144     /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
145     ///
146     /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
147     /// general.
148     ///
149     /// **Known problems:** None.
150     ///
151     /// **Example:**
152     /// ```rust,ignore
153     /// fn foo(bar: &Box<T>) { ... }
154     /// ```
155     ///
156     /// Better:
157     ///
158     /// ```rust,ignore
159     /// fn foo(bar: &T) { ... }
160     /// ```
161     pub BORROWED_BOX,
162     complexity,
163     "a borrow of a boxed type"
164 }
165
166 declare_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX]);
167
168 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
169     fn check_fn(&mut self, cx: &LateContext<'_, '_>, _: FnKind<'_>, decl: &FnDecl, _: &Body, _: Span, id: HirId) {
170         // Skip trait implementations; see issue #605.
171         if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id)) {
172             if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node {
173                 return;
174             }
175         }
176
177         check_fn_decl(cx, decl);
178     }
179
180     fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &hir::StructField) {
181         check_ty(cx, &field.ty, false);
182     }
183
184     fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, item: &TraitItem) {
185         match item.node {
186             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty, false),
187             TraitItemKind::Method(ref sig, _) => check_fn_decl(cx, &sig.decl),
188             _ => (),
189         }
190     }
191
192     fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &Local) {
193         if let Some(ref ty) = local.ty {
194             check_ty(cx, ty, true);
195         }
196     }
197 }
198
199 fn check_fn_decl(cx: &LateContext<'_, '_>, decl: &FnDecl) {
200     for input in &decl.inputs {
201         check_ty(cx, input, false);
202     }
203
204     if let FunctionRetTy::Return(ref ty) = decl.output {
205         check_ty(cx, ty, false);
206     }
207 }
208
209 /// Checks if `qpath` has last segment with type parameter matching `path`
210 fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str]) -> bool {
211     let last = last_path_segment(qpath);
212     if_chain! {
213         if let Some(ref params) = last.args;
214         if !params.parenthesized;
215         if let Some(ty) = params.args.iter().find_map(|arg| match arg {
216             GenericArg::Type(ty) => Some(ty),
217             _ => None,
218         });
219         if let TyKind::Path(ref qpath) = ty.node;
220         if let Some(did) = cx.tables.qpath_res(qpath, ty.hir_id).opt_def_id();
221         if match_def_path(cx, did, path);
222         then {
223             return true;
224         }
225     }
226     false
227 }
228
229 /// Recursively check for `TypePass` lints in the given type. Stop at the first
230 /// lint found.
231 ///
232 /// The parameter `is_local` distinguishes the context of the type; types from
233 /// local bindings should only be checked for the `BORROWED_BOX` lint.
234 #[allow(clippy::too_many_lines)]
235 fn check_ty(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool) {
236     if in_macro_or_desugar(hir_ty.span) {
237         return;
238     }
239     match hir_ty.node {
240         TyKind::Path(ref qpath) if !is_local => {
241             let hir_id = hir_ty.hir_id;
242             let res = cx.tables.qpath_res(qpath, hir_id);
243             if let Some(def_id) = res.opt_def_id() {
244                 if Some(def_id) == cx.tcx.lang_items().owned_box() {
245                     if match_type_parameter(cx, qpath, &paths::VEC) {
246                         span_help_and_lint(
247                             cx,
248                             BOX_VEC,
249                             hir_ty.span,
250                             "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
251                             "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
252                         );
253                         return; // don't recurse into the type
254                     }
255                 } else if match_def_path(cx, def_id, &paths::VEC) {
256                     if_chain! {
257                         // Get the _ part of Vec<_>
258                         if let Some(ref last) = last_path_segment(qpath).args;
259                         if let Some(ty) = last.args.iter().find_map(|arg| match arg {
260                             GenericArg::Type(ty) => Some(ty),
261                             _ => None,
262                         });
263                         // ty is now _ at this point
264                         if let TyKind::Path(ref ty_qpath) = ty.node;
265                         let res = cx.tables.qpath_res(ty_qpath, ty.hir_id);
266                         if let Some(def_id) = res.opt_def_id();
267                         if Some(def_id) == cx.tcx.lang_items().owned_box();
268                         // At this point, we know ty is Box<T>, now get T
269                         if let Some(ref last) = last_path_segment(ty_qpath).args;
270                         if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
271                             GenericArg::Type(ty) => Some(ty),
272                             _ => None,
273                         });
274                         then {
275                             let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
276                             if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env) {
277                                 span_lint_and_sugg(
278                                     cx,
279                                     VEC_BOX,
280                                     hir_ty.span,
281                                     "`Vec<T>` is already on the heap, the boxing is unnecessary.",
282                                     "try",
283                                     format!("Vec<{}>", ty_ty),
284                                     Applicability::MachineApplicable,
285                                 );
286                                 return; // don't recurse into the type
287                             }
288                         }
289                     }
290                 } else if match_def_path(cx, def_id, &paths::OPTION) {
291                     if match_type_parameter(cx, qpath, &paths::OPTION) {
292                         span_lint(
293                             cx,
294                             OPTION_OPTION,
295                             hir_ty.span,
296                             "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
297                              enum if you need to distinguish all 3 cases",
298                         );
299                         return; // don't recurse into the type
300                     }
301                 } else if match_def_path(cx, def_id, &paths::LINKED_LIST) {
302                     span_help_and_lint(
303                         cx,
304                         LINKEDLIST,
305                         hir_ty.span,
306                         "I see you're using a LinkedList! Perhaps you meant some other data structure?",
307                         "a VecDeque might work",
308                     );
309                     return; // don't recurse into the type
310                 }
311             }
312             match *qpath {
313                 QPath::Resolved(Some(ref ty), ref p) => {
314                     check_ty(cx, ty, is_local);
315                     for ty in p.segments.iter().flat_map(|seg| {
316                         seg.args
317                             .as_ref()
318                             .map_or_else(|| [].iter(), |params| params.args.iter())
319                             .filter_map(|arg| match arg {
320                                 GenericArg::Type(ty) => Some(ty),
321                                 _ => None,
322                             })
323                     }) {
324                         check_ty(cx, ty, is_local);
325                     }
326                 },
327                 QPath::Resolved(None, ref p) => {
328                     for ty in p.segments.iter().flat_map(|seg| {
329                         seg.args
330                             .as_ref()
331                             .map_or_else(|| [].iter(), |params| params.args.iter())
332                             .filter_map(|arg| match arg {
333                                 GenericArg::Type(ty) => Some(ty),
334                                 _ => None,
335                             })
336                     }) {
337                         check_ty(cx, ty, is_local);
338                     }
339                 },
340                 QPath::TypeRelative(ref ty, ref seg) => {
341                     check_ty(cx, ty, is_local);
342                     if let Some(ref params) = seg.args {
343                         for ty in params.args.iter().filter_map(|arg| match arg {
344                             GenericArg::Type(ty) => Some(ty),
345                             _ => None,
346                         }) {
347                             check_ty(cx, ty, is_local);
348                         }
349                     }
350                 },
351             }
352         },
353         TyKind::Rptr(ref lt, ref mut_ty) => check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
354         // recurse
355         TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => {
356             check_ty(cx, ty, is_local)
357         },
358         TyKind::Tup(ref tys) => {
359             for ty in tys {
360                 check_ty(cx, ty, is_local);
361             }
362         },
363         _ => {},
364     }
365 }
366
367 fn check_ty_rptr(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) {
368     match mut_ty.ty.node {
369         TyKind::Path(ref qpath) => {
370             let hir_id = mut_ty.ty.hir_id;
371             let def = cx.tables.qpath_res(qpath, hir_id);
372             if_chain! {
373                 if let Some(def_id) = def.opt_def_id();
374                 if Some(def_id) == cx.tcx.lang_items().owned_box();
375                 if let QPath::Resolved(None, ref path) = *qpath;
376                 if let [ref bx] = *path.segments;
377                 if let Some(ref params) = bx.args;
378                 if !params.parenthesized;
379                 if let Some(inner) = params.args.iter().find_map(|arg| match arg {
380                     GenericArg::Type(ty) => Some(ty),
381                     _ => None,
382                 });
383                 then {
384                     if is_any_trait(inner) {
385                         // Ignore `Box<Any>` types; see issue #1884 for details.
386                         return;
387                     }
388
389                     let ltopt = if lt.is_elided() {
390                         String::new()
391                     } else {
392                         format!("{} ", lt.name.ident().as_str())
393                     };
394                     let mutopt = if mut_ty.mutbl == Mutability::MutMutable {
395                         "mut "
396                     } else {
397                         ""
398                     };
399                     let mut applicability = Applicability::MachineApplicable;
400                     span_lint_and_sugg(
401                         cx,
402                         BORROWED_BOX,
403                         hir_ty.span,
404                         "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
405                         "try",
406                         format!(
407                             "&{}{}{}",
408                             ltopt,
409                             mutopt,
410                             &snippet_with_applicability(cx, inner.span, "..", &mut applicability)
411                         ),
412                         Applicability::Unspecified,
413                     );
414                     return; // don't recurse into the type
415                 }
416             };
417             check_ty(cx, &mut_ty.ty, is_local);
418         },
419         _ => check_ty(cx, &mut_ty.ty, is_local),
420     }
421 }
422
423 // Returns true if given type is `Any` trait.
424 fn is_any_trait(t: &hir::Ty) -> bool {
425     if_chain! {
426         if let TyKind::TraitObject(ref traits, _) = t.node;
427         if traits.len() >= 1;
428         // Only Send/Sync can be used as additional traits, so it is enough to
429         // check only the first trait.
430         if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
431         then {
432             return true;
433         }
434     }
435
436     false
437 }
438
439 declare_clippy_lint! {
440     /// **What it does:** Checks for binding a unit value.
441     ///
442     /// **Why is this bad?** A unit value cannot usefully be used anywhere. So
443     /// binding one is kind of pointless.
444     ///
445     /// **Known problems:** None.
446     ///
447     /// **Example:**
448     /// ```rust
449     /// let x = {
450     ///     1;
451     /// };
452     /// ```
453     pub LET_UNIT_VALUE,
454     style,
455     "creating a let binding to a value of unit type, which usually can't be used afterwards"
456 }
457
458 declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]);
459
460 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnitValue {
461     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
462         if let StmtKind::Local(ref local) = stmt.node {
463             if is_unit(cx.tables.pat_ty(&local.pat)) {
464                 if in_external_macro(cx.sess(), stmt.span) || in_macro_or_desugar(local.pat.span) {
465                     return;
466                 }
467                 if higher::is_from_for_desugar(local) {
468                     return;
469                 }
470                 span_lint(
471                     cx,
472                     LET_UNIT_VALUE,
473                     stmt.span,
474                     &format!(
475                         "this let-binding has unit value. Consider omitting `let {} =`",
476                         snippet(cx, local.pat.span, "..")
477                     ),
478                 );
479             }
480         }
481     }
482 }
483
484 declare_clippy_lint! {
485     /// **What it does:** Checks for comparisons to unit.
486     ///
487     /// **Why is this bad?** Unit is always equal to itself, and thus is just a
488     /// clumsily written constant. Mostly this happens when someone accidentally
489     /// adds semicolons at the end of the operands.
490     ///
491     /// **Known problems:** None.
492     ///
493     /// **Example:**
494     /// ```rust
495     /// # fn foo() {};
496     /// # fn bar() {};
497     /// # fn baz() {};
498     /// if {
499     ///     foo();
500     /// } == {
501     ///     bar();
502     /// } {
503     ///     baz();
504     /// }
505     /// ```
506     /// is equal to
507     /// ```rust
508     /// # fn foo() {};
509     /// # fn bar() {};
510     /// # fn baz() {};
511     /// {
512     ///     foo();
513     ///     bar();
514     ///     baz();
515     /// }
516     /// ```
517     pub UNIT_CMP,
518     correctness,
519     "comparing unit values"
520 }
521
522 declare_lint_pass!(UnitCmp => [UNIT_CMP]);
523
524 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
525     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
526         if in_macro_or_desugar(expr.span) {
527             return;
528         }
529         if let ExprKind::Binary(ref cmp, ref left, _) = expr.node {
530             let op = cmp.node;
531             if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
532                 let result = match op {
533                     BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
534                     _ => "false",
535                 };
536                 span_lint(
537                     cx,
538                     UNIT_CMP,
539                     expr.span,
540                     &format!(
541                         "{}-comparison of unit values detected. This will always be {}",
542                         op.as_str(),
543                         result
544                     ),
545                 );
546             }
547         }
548     }
549 }
550
551 declare_clippy_lint! {
552     /// **What it does:** Checks for passing a unit value as an argument to a function without using a
553     /// unit literal (`()`).
554     ///
555     /// **Why is this bad?** This is likely the result of an accidental semicolon.
556     ///
557     /// **Known problems:** None.
558     ///
559     /// **Example:**
560     /// ```rust
561     /// foo({
562     ///     let a = bar();
563     ///     baz(a);
564     /// })
565     /// ```
566     pub UNIT_ARG,
567     complexity,
568     "passing unit to a function"
569 }
570
571 declare_lint_pass!(UnitArg => [UNIT_ARG]);
572
573 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg {
574     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
575         if in_macro_or_desugar(expr.span) {
576             return;
577         }
578
579         // apparently stuff in the desugaring of `?` can trigger this
580         // so check for that here
581         // only the calls to `Try::from_error` is marked as desugared,
582         // so we need to check both the current Expr and its parent.
583         if is_questionmark_desugar_marked_call(expr) {
584             return;
585         }
586         if_chain! {
587             let map = &cx.tcx.hir();
588             let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
589             if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
590             if is_questionmark_desugar_marked_call(parent_expr);
591             then {
592                 return;
593             }
594         }
595
596         match expr.node {
597             ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
598                 for arg in args {
599                     if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
600                         if let ExprKind::Match(.., match_source) = &arg.node {
601                             if *match_source == MatchSource::TryDesugar {
602                                 continue;
603                             }
604                         }
605
606                         span_lint_and_sugg(
607                             cx,
608                             UNIT_ARG,
609                             arg.span,
610                             "passing a unit value to a function",
611                             "if you intended to pass a unit value, use a unit literal instead",
612                             "()".to_string(),
613                             Applicability::MachineApplicable,
614                         );
615                     }
616                 }
617             },
618             _ => (),
619         }
620     }
621 }
622
623 fn is_questionmark_desugar_marked_call(expr: &Expr) -> bool {
624     use syntax_pos::hygiene::DesugaringKind;
625     if let ExprKind::Call(ref callee, _) = expr.node {
626         callee.span.is_desugaring(DesugaringKind::QuestionMark)
627     } else {
628         false
629     }
630 }
631
632 fn is_unit(ty: Ty<'_>) -> bool {
633     match ty.sty {
634         ty::Tuple(slice) if slice.is_empty() => true,
635         _ => false,
636     }
637 }
638
639 fn is_unit_literal(expr: &Expr) -> bool {
640     match expr.node {
641         ExprKind::Tup(ref slice) if slice.is_empty() => true,
642         _ => false,
643     }
644 }
645
646 declare_clippy_lint! {
647     /// **What it does:** Checks for casts from any numerical to a float type where
648     /// the receiving type cannot store all values from the original type without
649     /// rounding errors. This possible rounding is to be expected, so this lint is
650     /// `Allow` by default.
651     ///
652     /// Basically, this warns on casting any integer with 32 or more bits to `f32`
653     /// or any 64-bit integer to `f64`.
654     ///
655     /// **Why is this bad?** It's not bad at all. But in some applications it can be
656     /// helpful to know where precision loss can take place. This lint can help find
657     /// those places in the code.
658     ///
659     /// **Known problems:** None.
660     ///
661     /// **Example:**
662     /// ```rust
663     /// let x = u64::MAX;
664     /// x as f64
665     /// ```
666     pub CAST_PRECISION_LOSS,
667     pedantic,
668     "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
669 }
670
671 declare_clippy_lint! {
672     /// **What it does:** Checks for casts from a signed to an unsigned numerical
673     /// type. In this case, negative values wrap around to large positive values,
674     /// which can be quite surprising in practice. However, as the cast works as
675     /// defined, this lint is `Allow` by default.
676     ///
677     /// **Why is this bad?** Possibly surprising results. You can activate this lint
678     /// as a one-time check to see where numerical wrapping can arise.
679     ///
680     /// **Known problems:** None.
681     ///
682     /// **Example:**
683     /// ```rust
684     /// let y: i8 = -1;
685     /// y as u128 // will return 18446744073709551615
686     /// ```
687     pub CAST_SIGN_LOSS,
688     pedantic,
689     "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
690 }
691
692 declare_clippy_lint! {
693     /// **What it does:** Checks for on casts between numerical types that may
694     /// truncate large values. This is expected behavior, so the cast is `Allow` by
695     /// default.
696     ///
697     /// **Why is this bad?** In some problem domains, it is good practice to avoid
698     /// truncation. This lint can be activated to help assess where additional
699     /// checks could be beneficial.
700     ///
701     /// **Known problems:** None.
702     ///
703     /// **Example:**
704     /// ```rust
705     /// fn as_u8(x: u64) -> u8 {
706     ///     x as u8
707     /// }
708     /// ```
709     pub CAST_POSSIBLE_TRUNCATION,
710     pedantic,
711     "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
712 }
713
714 declare_clippy_lint! {
715     /// **What it does:** Checks for casts from an unsigned type to a signed type of
716     /// the same size. Performing such a cast is a 'no-op' for the compiler,
717     /// i.e., nothing is changed at the bit level, and the binary representation of
718     /// the value is reinterpreted. This can cause wrapping if the value is too big
719     /// for the target signed type. However, the cast works as defined, so this lint
720     /// is `Allow` by default.
721     ///
722     /// **Why is this bad?** While such a cast is not bad in itself, the results can
723     /// be surprising when this is not the intended behavior, as demonstrated by the
724     /// example below.
725     ///
726     /// **Known problems:** None.
727     ///
728     /// **Example:**
729     /// ```rust
730     /// u32::MAX as i32 // will yield a value of `-1`
731     /// ```
732     pub CAST_POSSIBLE_WRAP,
733     pedantic,
734     "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
735 }
736
737 declare_clippy_lint! {
738     /// **What it does:** Checks for on casts between numerical types that may
739     /// be replaced by safe conversion functions.
740     ///
741     /// **Why is this bad?** Rust's `as` keyword will perform many kinds of
742     /// conversions, including silently lossy conversions. Conversion functions such
743     /// as `i32::from` will only perform lossless conversions. Using the conversion
744     /// functions prevents conversions from turning into silent lossy conversions if
745     /// the types of the input expressions ever change, and make it easier for
746     /// people reading the code to know that the conversion is lossless.
747     ///
748     /// **Known problems:** None.
749     ///
750     /// **Example:**
751     /// ```rust
752     /// fn as_u64(x: u8) -> u64 {
753     ///     x as u64
754     /// }
755     /// ```
756     ///
757     /// Using `::from` would look like this:
758     ///
759     /// ```rust
760     /// fn as_u64(x: u8) -> u64 {
761     ///     u64::from(x)
762     /// }
763     /// ```
764     pub CAST_LOSSLESS,
765     complexity,
766     "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
767 }
768
769 declare_clippy_lint! {
770     /// **What it does:** Checks for casts to the same type.
771     ///
772     /// **Why is this bad?** It's just unnecessary.
773     ///
774     /// **Known problems:** None.
775     ///
776     /// **Example:**
777     /// ```rust
778     /// let _ = 2i32 as i32
779     /// ```
780     pub UNNECESSARY_CAST,
781     complexity,
782     "cast to the same type, e.g., `x as i32` where `x: i32`"
783 }
784
785 declare_clippy_lint! {
786     /// **What it does:** Checks for casts from a less-strictly-aligned pointer to a
787     /// more-strictly-aligned pointer
788     ///
789     /// **Why is this bad?** Dereferencing the resulting pointer may be undefined
790     /// behavior.
791     ///
792     /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
793     /// on the resulting pointer is fine.
794     ///
795     /// **Example:**
796     /// ```rust
797     /// let _ = (&1u8 as *const u8) as *const u16;
798     /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
799     /// ```
800     pub CAST_PTR_ALIGNMENT,
801     correctness,
802     "cast from a pointer to a more-strictly-aligned pointer"
803 }
804
805 declare_clippy_lint! {
806     /// **What it does:** Checks for casts of function pointers to something other than usize
807     ///
808     /// **Why is this bad?**
809     /// Casting a function pointer to anything other than usize/isize is not portable across
810     /// architectures, because you end up losing bits if the target type is too small or end up with a
811     /// bunch of extra bits that waste space and add more instructions to the final binary than
812     /// strictly necessary for the problem
813     ///
814     /// Casting to isize also doesn't make sense since there are no signed addresses.
815     ///
816     /// **Example**
817     ///
818     /// ```rust
819     /// // Bad
820     /// fn fun() -> i32 { 1 }
821     /// let a = fun as i64;
822     ///
823     /// // Good
824     /// fn fun2() -> i32 { 1 }
825     /// let a = fun2 as usize;
826     /// ```
827     pub FN_TO_NUMERIC_CAST,
828     style,
829     "casting a function pointer to a numeric type other than usize"
830 }
831
832 declare_clippy_lint! {
833     /// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to
834     /// store address.
835     ///
836     /// **Why is this bad?**
837     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
838     /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
839     /// a comment) to perform the truncation.
840     ///
841     /// **Example**
842     ///
843     /// ```rust
844     /// // Bad
845     /// fn fn1() -> i16 {
846     ///     1
847     /// };
848     /// let _ = fn1 as i32;
849     ///
850     /// // Better: Cast to usize first, then comment with the reason for the truncation
851     /// fn fn2() -> i16 {
852     ///     1
853     /// };
854     /// let fn_ptr = fn2 as usize;
855     /// let fn_ptr_truncated = fn_ptr as i32;
856     /// ```
857     pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
858     style,
859     "casting a function pointer to a numeric type not wide enough to store the address"
860 }
861
862 /// Returns the size in bits of an integral type.
863 /// Will return 0 if the type is not an int or uint variant
864 fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
865     match typ.sty {
866         ty::Int(i) => match i {
867             IntTy::Isize => tcx.data_layout.pointer_size.bits(),
868             IntTy::I8 => 8,
869             IntTy::I16 => 16,
870             IntTy::I32 => 32,
871             IntTy::I64 => 64,
872             IntTy::I128 => 128,
873         },
874         ty::Uint(i) => match i {
875             UintTy::Usize => tcx.data_layout.pointer_size.bits(),
876             UintTy::U8 => 8,
877             UintTy::U16 => 16,
878             UintTy::U32 => 32,
879             UintTy::U64 => 64,
880             UintTy::U128 => 128,
881         },
882         _ => 0,
883     }
884 }
885
886 fn is_isize_or_usize(typ: Ty<'_>) -> bool {
887     match typ.sty {
888         ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => true,
889         _ => false,
890     }
891 }
892
893 fn span_precision_loss_lint(cx: &LateContext<'_, '_>, expr: &Expr, cast_from: Ty<'_>, cast_to_f64: bool) {
894     let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
895     let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
896     let arch_dependent_str = "on targets with 64-bit wide pointers ";
897     let from_nbits_str = if arch_dependent {
898         "64".to_owned()
899     } else if is_isize_or_usize(cast_from) {
900         "32 or 64".to_owned()
901     } else {
902         int_ty_to_nbits(cast_from, cx.tcx).to_string()
903     };
904     span_lint(
905         cx,
906         CAST_PRECISION_LOSS,
907         expr.span,
908         &format!(
909             "casting {0} to {1} causes a loss of precision {2}({0} is {3} bits wide, but {1}'s mantissa \
910              is only {4} bits wide)",
911             cast_from,
912             if cast_to_f64 { "f64" } else { "f32" },
913             if arch_dependent { arch_dependent_str } else { "" },
914             from_nbits_str,
915             mantissa_nbits
916         ),
917     );
918 }
919
920 fn should_strip_parens(op: &Expr, snip: &str) -> bool {
921     if let ExprKind::Binary(_, _, _) = op.node {
922         if snip.starts_with('(') && snip.ends_with(')') {
923             return true;
924         }
925     }
926     false
927 }
928
929 fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
930     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
931     if in_constant(cx, expr.hir_id) {
932         return;
933     }
934     // The suggestion is to use a function call, so if the original expression
935     // has parens on the outside, they are no longer needed.
936     let mut applicability = Applicability::MachineApplicable;
937     let opt = snippet_opt(cx, op.span);
938     let sugg = if let Some(ref snip) = opt {
939         if should_strip_parens(op, snip) {
940             &snip[1..snip.len() - 1]
941         } else {
942             snip.as_str()
943         }
944     } else {
945         applicability = Applicability::HasPlaceholders;
946         ".."
947     };
948
949     span_lint_and_sugg(
950         cx,
951         CAST_LOSSLESS,
952         expr.span,
953         &format!(
954             "casting {} to {} may become silently lossy if you later change the type",
955             cast_from, cast_to
956         ),
957         "try",
958         format!("{}::from({})", cast_to, sugg),
959         applicability,
960     );
961 }
962
963 enum ArchSuffix {
964     _32,
965     _64,
966     None,
967 }
968
969 fn check_loss_of_sign(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
970     if !cast_from.is_signed() || cast_to.is_signed() {
971         return;
972     }
973
974     // don't lint for positive constants
975     let const_val = constant(cx, &cx.tables, op);
976     if_chain! {
977         if let Some((const_val, _)) = const_val;
978         if let Constant::Int(n) = const_val;
979         if let ty::Int(ity) = cast_from.sty;
980         if sext(cx.tcx, n, ity) >= 0;
981         then {
982             return
983         }
984     }
985
986     span_lint(
987         cx,
988         CAST_SIGN_LOSS,
989         expr.span,
990         &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to),
991     );
992 }
993
994 fn check_truncation_and_wrapping(cx: &LateContext<'_, '_>, expr: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
995     let arch_64_suffix = " on targets with 64-bit wide pointers";
996     let arch_32_suffix = " on targets with 32-bit wide pointers";
997     let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
998     let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
999     let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1000     let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) =
1001         match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
1002             (true, true) | (false, false) => (
1003                 to_nbits < from_nbits,
1004                 ArchSuffix::None,
1005                 to_nbits == from_nbits && cast_unsigned_to_signed,
1006                 ArchSuffix::None,
1007             ),
1008             (true, false) => (
1009                 to_nbits <= 32,
1010                 if to_nbits == 32 {
1011                     ArchSuffix::_64
1012                 } else {
1013                     ArchSuffix::None
1014                 },
1015                 to_nbits <= 32 && cast_unsigned_to_signed,
1016                 ArchSuffix::_32,
1017             ),
1018             (false, true) => (
1019                 from_nbits == 64,
1020                 ArchSuffix::_32,
1021                 cast_unsigned_to_signed,
1022                 if from_nbits == 64 {
1023                     ArchSuffix::_64
1024                 } else {
1025                     ArchSuffix::_32
1026                 },
1027             ),
1028         };
1029     if span_truncation {
1030         span_lint(
1031             cx,
1032             CAST_POSSIBLE_TRUNCATION,
1033             expr.span,
1034             &format!(
1035                 "casting {} to {} may truncate the value{}",
1036                 cast_from,
1037                 cast_to,
1038                 match suffix_truncation {
1039                     ArchSuffix::_32 => arch_32_suffix,
1040                     ArchSuffix::_64 => arch_64_suffix,
1041                     ArchSuffix::None => "",
1042                 }
1043             ),
1044         );
1045     }
1046     if span_wrap {
1047         span_lint(
1048             cx,
1049             CAST_POSSIBLE_WRAP,
1050             expr.span,
1051             &format!(
1052                 "casting {} to {} may wrap around the value{}",
1053                 cast_from,
1054                 cast_to,
1055                 match suffix_wrap {
1056                     ArchSuffix::_32 => arch_32_suffix,
1057                     ArchSuffix::_64 => arch_64_suffix,
1058                     ArchSuffix::None => "",
1059                 }
1060             ),
1061         );
1062     }
1063 }
1064
1065 fn check_lossless(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1066     let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
1067     let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
1068     let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1069     if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned
1070     {
1071         span_lossless_lint(cx, expr, op, cast_from, cast_to);
1072     }
1073 }
1074
1075 declare_lint_pass!(Casts => [
1076     CAST_PRECISION_LOSS,
1077     CAST_SIGN_LOSS,
1078     CAST_POSSIBLE_TRUNCATION,
1079     CAST_POSSIBLE_WRAP,
1080     CAST_LOSSLESS,
1081     UNNECESSARY_CAST,
1082     CAST_PTR_ALIGNMENT,
1083     FN_TO_NUMERIC_CAST,
1084     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
1085 ]);
1086
1087 // Check if the given type is either `core::ffi::c_void` or
1088 // one of the platform specific `libc::<platform>::c_void` of libc.
1089 fn is_c_void(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
1090     if let ty::Adt(adt, _) = ty.sty {
1091         let names = cx.get_def_path(adt.did);
1092
1093         if names.is_empty() {
1094             return false;
1095         }
1096         if names[0] == sym!(libc) || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) {
1097             return true;
1098         }
1099     }
1100     false
1101 }
1102
1103 /// Returns the mantissa bits wide of a fp type.
1104 /// Will return 0 if the type is not a fp
1105 fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
1106     match typ.sty {
1107         ty::Float(FloatTy::F32) => 23,
1108         ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
1109         _ => 0,
1110     }
1111 }
1112
1113 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Casts {
1114     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
1115         if in_macro_or_desugar(expr.span) {
1116             return;
1117         }
1118         if let ExprKind::Cast(ref ex, _) = expr.node {
1119             let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
1120             lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
1121             if let ExprKind::Lit(ref lit) = ex.node {
1122                 use syntax::ast::{LitIntType, LitKind};
1123                 if let LitKind::Int(n, _) = lit.node {
1124                     if cast_to.is_floating_point() {
1125                         let from_nbits = 128 - n.leading_zeros();
1126                         let to_nbits = fp_ty_mantissa_nbits(cast_to);
1127                         if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits {
1128                             span_lint_and_sugg(
1129                                 cx,
1130                                 UNNECESSARY_CAST,
1131                                 expr.span,
1132                                 &format!("casting integer literal to {} is unnecessary", cast_to),
1133                                 "try",
1134                                 format!("{}_{}", n, cast_to),
1135                                 Applicability::MachineApplicable,
1136                             );
1137                             return;
1138                         }
1139                     }
1140                 }
1141                 match lit.node {
1142                     LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::FloatUnsuffixed(_) => {},
1143                     _ => {
1144                         if cast_from.sty == cast_to.sty && !in_external_macro(cx.sess(), expr.span) {
1145                             span_lint(
1146                                 cx,
1147                                 UNNECESSARY_CAST,
1148                                 expr.span,
1149                                 &format!(
1150                                     "casting to the same type is unnecessary (`{}` -> `{}`)",
1151                                     cast_from, cast_to
1152                                 ),
1153                             );
1154                         }
1155                     },
1156                 }
1157             }
1158             if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
1159                 match (cast_from.is_integral(), cast_to.is_integral()) {
1160                     (true, false) => {
1161                         let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
1162                         let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.sty {
1163                             32
1164                         } else {
1165                             64
1166                         };
1167                         if is_isize_or_usize(cast_from) || from_nbits >= to_nbits {
1168                             span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64);
1169                         }
1170                         if from_nbits < to_nbits {
1171                             span_lossless_lint(cx, expr, ex, cast_from, cast_to);
1172                         }
1173                     },
1174                     (false, true) => {
1175                         span_lint(
1176                             cx,
1177                             CAST_POSSIBLE_TRUNCATION,
1178                             expr.span,
1179                             &format!("casting {} to {} may truncate the value", cast_from, cast_to),
1180                         );
1181                         if !cast_to.is_signed() {
1182                             span_lint(
1183                                 cx,
1184                                 CAST_SIGN_LOSS,
1185                                 expr.span,
1186                                 &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to),
1187                             );
1188                         }
1189                     },
1190                     (true, true) => {
1191                         check_loss_of_sign(cx, expr, ex, cast_from, cast_to);
1192                         check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
1193                         check_lossless(cx, expr, ex, cast_from, cast_to);
1194                     },
1195                     (false, false) => {
1196                         if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.sty, &cast_to.sty) {
1197                             span_lint(
1198                                 cx,
1199                                 CAST_POSSIBLE_TRUNCATION,
1200                                 expr.span,
1201                                 "casting f64 to f32 may truncate the value",
1202                             );
1203                         }
1204                         if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.sty, &cast_to.sty) {
1205                             span_lossless_lint(cx, expr, ex, cast_from, cast_to);
1206                         }
1207                     },
1208                 }
1209             }
1210
1211             if_chain! {
1212                 if let ty::RawPtr(from_ptr_ty) = &cast_from.sty;
1213                 if let ty::RawPtr(to_ptr_ty) = &cast_to.sty;
1214                 if let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty);
1215                 if let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty);
1216                 if from_layout.align.abi < to_layout.align.abi;
1217                 // with c_void, we inherently need to trust the user
1218                 if !is_c_void(cx, from_ptr_ty.ty);
1219                 // when casting from a ZST, we don't know enough to properly lint
1220                 if !from_layout.is_zst();
1221                 then {
1222                     span_lint(
1223                         cx,
1224                         CAST_PTR_ALIGNMENT,
1225                         expr.span,
1226                         &format!(
1227                             "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)",
1228                             cast_from,
1229                             cast_to,
1230                             from_layout.align.abi.bytes(),
1231                             to_layout.align.abi.bytes(),
1232                         ),
1233                     );
1234                 }
1235             }
1236         }
1237     }
1238 }
1239
1240 fn lint_fn_to_numeric_cast(
1241     cx: &LateContext<'_, '_>,
1242     expr: &Expr,
1243     cast_expr: &Expr,
1244     cast_from: Ty<'_>,
1245     cast_to: Ty<'_>,
1246 ) {
1247     // We only want to check casts to `ty::Uint` or `ty::Int`
1248     match cast_to.sty {
1249         ty::Uint(_) | ty::Int(..) => { /* continue on */ },
1250         _ => return,
1251     }
1252     match cast_from.sty {
1253         ty::FnDef(..) | ty::FnPtr(_) => {
1254             let mut applicability = Applicability::MachineApplicable;
1255             let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
1256
1257             let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1258             if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
1259                 span_lint_and_sugg(
1260                     cx,
1261                     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
1262                     expr.span,
1263                     &format!(
1264                         "casting function pointer `{}` to `{}`, which truncates the value",
1265                         from_snippet, cast_to
1266                     ),
1267                     "try",
1268                     format!("{} as usize", from_snippet),
1269                     applicability,
1270                 );
1271             } else if cast_to.sty != ty::Uint(UintTy::Usize) {
1272                 span_lint_and_sugg(
1273                     cx,
1274                     FN_TO_NUMERIC_CAST,
1275                     expr.span,
1276                     &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
1277                     "try",
1278                     format!("{} as usize", from_snippet),
1279                     applicability,
1280                 );
1281             }
1282         },
1283         _ => {},
1284     }
1285 }
1286
1287 declare_clippy_lint! {
1288     /// **What it does:** Checks for types used in structs, parameters and `let`
1289     /// declarations above a certain complexity threshold.
1290     ///
1291     /// **Why is this bad?** Too complex types make the code less readable. Consider
1292     /// using a `type` definition to simplify them.
1293     ///
1294     /// **Known problems:** None.
1295     ///
1296     /// **Example:**
1297     /// ```rust
1298     /// struct Foo {
1299     ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
1300     /// }
1301     /// ```
1302     pub TYPE_COMPLEXITY,
1303     complexity,
1304     "usage of very complex types that might be better factored into `type` definitions"
1305 }
1306
1307 pub struct TypeComplexity {
1308     threshold: u64,
1309 }
1310
1311 impl TypeComplexity {
1312     pub fn new(threshold: u64) -> Self {
1313         Self { threshold }
1314     }
1315 }
1316
1317 impl_lint_pass!(TypeComplexity => [TYPE_COMPLEXITY]);
1318
1319 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexity {
1320     fn check_fn(
1321         &mut self,
1322         cx: &LateContext<'a, 'tcx>,
1323         _: FnKind<'tcx>,
1324         decl: &'tcx FnDecl,
1325         _: &'tcx Body,
1326         _: Span,
1327         _: HirId,
1328     ) {
1329         self.check_fndecl(cx, decl);
1330     }
1331
1332     fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
1333         // enum variants are also struct fields now
1334         self.check_type(cx, &field.ty);
1335     }
1336
1337     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
1338         match item.node {
1339             ItemKind::Static(ref ty, _, _) | ItemKind::Const(ref ty, _) => self.check_type(cx, ty),
1340             // functions, enums, structs, impls and traits are covered
1341             _ => (),
1342         }
1343     }
1344
1345     fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
1346         match item.node {
1347             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty),
1348             TraitItemKind::Method(MethodSig { ref decl, .. }, TraitMethod::Required(_)) => self.check_fndecl(cx, decl),
1349             // methods with default impl are covered by check_fn
1350             _ => (),
1351         }
1352     }
1353
1354     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
1355         match item.node {
1356             ImplItemKind::Const(ref ty, _) | ImplItemKind::Type(ref ty) => self.check_type(cx, ty),
1357             // methods are covered by check_fn
1358             _ => (),
1359         }
1360     }
1361
1362     fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
1363         if let Some(ref ty) = local.ty {
1364             self.check_type(cx, ty);
1365         }
1366     }
1367 }
1368
1369 impl<'a, 'tcx> TypeComplexity {
1370     fn check_fndecl(&self, cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl) {
1371         for arg in &decl.inputs {
1372             self.check_type(cx, arg);
1373         }
1374         if let Return(ref ty) = decl.output {
1375             self.check_type(cx, ty);
1376         }
1377     }
1378
1379     fn check_type(&self, cx: &LateContext<'_, '_>, ty: &hir::Ty) {
1380         if in_macro_or_desugar(ty.span) {
1381             return;
1382         }
1383         let score = {
1384             let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
1385             visitor.visit_ty(ty);
1386             visitor.score
1387         };
1388
1389         if score > self.threshold {
1390             span_lint(
1391                 cx,
1392                 TYPE_COMPLEXITY,
1393                 ty.span,
1394                 "very complex type used. Consider factoring parts into `type` definitions",
1395             );
1396         }
1397     }
1398 }
1399
1400 /// Walks a type and assigns a complexity score to it.
1401 struct TypeComplexityVisitor {
1402     /// total complexity score of the type
1403     score: u64,
1404     /// current nesting level
1405     nest: u64,
1406 }
1407
1408 impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
1409     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
1410         let (add_score, sub_nest) = match ty.node {
1411             // _, &x and *x have only small overhead; don't mess with nesting level
1412             TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
1413
1414             // the "normal" components of a type: named types, arrays/tuples
1415             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
1416
1417             // function types bring a lot of overhead
1418             TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
1419
1420             TyKind::TraitObject(ref param_bounds, _) => {
1421                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
1422                     bound.bound_generic_params.iter().any(|gen| match gen.kind {
1423                         GenericParamKind::Lifetime { .. } => true,
1424                         _ => false,
1425                     })
1426                 });
1427                 if has_lifetime_parameters {
1428                     // complex trait bounds like A<'a, 'b>
1429                     (50 * self.nest, 1)
1430                 } else {
1431                     // simple trait bounds like A + B
1432                     (20 * self.nest, 0)
1433                 }
1434             },
1435
1436             _ => (0, 0),
1437         };
1438         self.score += add_score;
1439         self.nest += sub_nest;
1440         walk_ty(self, ty);
1441         self.nest -= sub_nest;
1442     }
1443     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
1444         NestedVisitorMap::None
1445     }
1446 }
1447
1448 declare_clippy_lint! {
1449     /// **What it does:** Checks for expressions where a character literal is cast
1450     /// to `u8` and suggests using a byte literal instead.
1451     ///
1452     /// **Why is this bad?** In general, casting values to smaller types is
1453     /// error-prone and should be avoided where possible. In the particular case of
1454     /// converting a character literal to u8, it is easy to avoid by just using a
1455     /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
1456     /// than `'a' as u8`.
1457     ///
1458     /// **Known problems:** None.
1459     ///
1460     /// **Example:**
1461     /// ```rust
1462     /// 'x' as u8
1463     /// ```
1464     ///
1465     /// A better version, using the byte literal:
1466     ///
1467     /// ```rust
1468     /// b'x'
1469     /// ```
1470     pub CHAR_LIT_AS_U8,
1471     complexity,
1472     "casting a character literal to u8"
1473 }
1474
1475 declare_lint_pass!(CharLitAsU8 => [CHAR_LIT_AS_U8]);
1476
1477 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 {
1478     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
1479         use syntax::ast::LitKind;
1480
1481         if let ExprKind::Cast(ref e, _) = expr.node {
1482             if let ExprKind::Lit(ref l) = e.node {
1483                 if let LitKind::Char(_) = l.node {
1484                     if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).sty && !in_macro_or_desugar(expr.span) {
1485                         let msg = "casting character literal to u8. `char`s \
1486                                    are 4 bytes wide in rust, so casting to u8 \
1487                                    truncates them";
1488                         let help = format!(
1489                             "Consider using a byte literal instead:\nb{}",
1490                             snippet(cx, e.span, "'x'")
1491                         );
1492                         span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help);
1493                     }
1494                 }
1495             }
1496         }
1497     }
1498 }
1499
1500 declare_clippy_lint! {
1501     /// **What it does:** Checks for comparisons where one side of the relation is
1502     /// either the minimum or maximum value for its type and warns if it involves a
1503     /// case that is always true or always false. Only integer and boolean types are
1504     /// checked.
1505     ///
1506     /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
1507     /// that it is possible for `x` to be less than the minimum. Expressions like
1508     /// `max < x` are probably mistakes.
1509     ///
1510     /// **Known problems:** For `usize` the size of the current compile target will
1511     /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
1512     /// a comparison to detect target pointer width will trigger this lint. One can
1513     /// use `mem::sizeof` and compare its value or conditional compilation
1514     /// attributes
1515     /// like `#[cfg(target_pointer_width = "64")] ..` instead.
1516     ///
1517     /// **Example:**
1518     ///
1519     /// ```rust
1520     /// let vec: Vec<isize> = vec![];
1521     /// if vec.len() <= 0 {}
1522     /// if 100 > std::i32::MAX {}
1523     /// ```
1524     pub ABSURD_EXTREME_COMPARISONS,
1525     correctness,
1526     "a comparison with a maximum or minimum value that is always true or false"
1527 }
1528
1529 declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
1530
1531 enum ExtremeType {
1532     Minimum,
1533     Maximum,
1534 }
1535
1536 struct ExtremeExpr<'a> {
1537     which: ExtremeType,
1538     expr: &'a Expr,
1539 }
1540
1541 enum AbsurdComparisonResult {
1542     AlwaysFalse,
1543     AlwaysTrue,
1544     InequalityImpossible,
1545 }
1546
1547 fn is_cast_between_fixed_and_target<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
1548     if let ExprKind::Cast(ref cast_exp, _) = expr.node {
1549         let precast_ty = cx.tables.expr_ty(cast_exp);
1550         let cast_ty = cx.tables.expr_ty(expr);
1551
1552         return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
1553     }
1554
1555     false
1556 }
1557
1558 fn detect_absurd_comparison<'a, 'tcx>(
1559     cx: &LateContext<'a, 'tcx>,
1560     op: BinOpKind,
1561     lhs: &'tcx Expr,
1562     rhs: &'tcx Expr,
1563 ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
1564     use crate::types::AbsurdComparisonResult::*;
1565     use crate::types::ExtremeType::*;
1566     use crate::utils::comparisons::*;
1567
1568     // absurd comparison only makes sense on primitive types
1569     // primitive types don't implement comparison operators with each other
1570     if cx.tables.expr_ty(lhs) != cx.tables.expr_ty(rhs) {
1571         return None;
1572     }
1573
1574     // comparisons between fix sized types and target sized types are considered unanalyzable
1575     if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
1576         return None;
1577     }
1578
1579     let normalized = normalize_comparison(op, lhs, rhs);
1580     let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
1581         val
1582     } else {
1583         return None;
1584     };
1585
1586     let lx = detect_extreme_expr(cx, normalized_lhs);
1587     let rx = detect_extreme_expr(cx, normalized_rhs);
1588
1589     Some(match rel {
1590         Rel::Lt => {
1591             match (lx, rx) {
1592                 (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
1593                 (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
1594                 _ => return None,
1595             }
1596         },
1597         Rel::Le => {
1598             match (lx, rx) {
1599                 (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
1600                 (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
1601                 (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
1602                 (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
1603                 _ => return None,
1604             }
1605         },
1606         Rel::Ne | Rel::Eq => return None,
1607     })
1608 }
1609
1610 fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option<ExtremeExpr<'tcx>> {
1611     use crate::types::ExtremeType::*;
1612
1613     let ty = cx.tables.expr_ty(expr);
1614
1615     let cv = constant(cx, cx.tables, expr)?.0;
1616
1617     let which = match (&ty.sty, cv) {
1618         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
1619         (&ty::Int(ity), Constant::Int(i))
1620             if i == unsext(cx.tcx, i128::min_value() >> (128 - int_bits(cx.tcx, ity)), ity) =>
1621         {
1622             Minimum
1623         },
1624
1625         (&ty::Bool, Constant::Bool(true)) => Maximum,
1626         (&ty::Int(ity), Constant::Int(i))
1627             if i == unsext(cx.tcx, i128::max_value() >> (128 - int_bits(cx.tcx, ity)), ity) =>
1628         {
1629             Maximum
1630         },
1631         (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::max_value(), uty) == i => Maximum,
1632
1633         _ => return None,
1634     };
1635     Some(ExtremeExpr { which, expr })
1636 }
1637
1638 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons {
1639     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
1640         use crate::types::AbsurdComparisonResult::*;
1641         use crate::types::ExtremeType::*;
1642
1643         if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.node {
1644             if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
1645                 if !in_macro_or_desugar(expr.span) {
1646                     let msg = "this comparison involving the minimum or maximum element for this \
1647                                type contains a case that is always true or always false";
1648
1649                     let conclusion = match result {
1650                         AlwaysFalse => "this comparison is always false".to_owned(),
1651                         AlwaysTrue => "this comparison is always true".to_owned(),
1652                         InequalityImpossible => format!(
1653                             "the case where the two sides are not equal never occurs, consider using {} == {} \
1654                              instead",
1655                             snippet(cx, lhs.span, "lhs"),
1656                             snippet(cx, rhs.span, "rhs")
1657                         ),
1658                     };
1659
1660                     let help = format!(
1661                         "because {} is the {} value for this type, {}",
1662                         snippet(cx, culprit.expr.span, "x"),
1663                         match culprit.which {
1664                             Minimum => "minimum",
1665                             Maximum => "maximum",
1666                         },
1667                         conclusion
1668                     );
1669
1670                     span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help);
1671                 }
1672             }
1673         }
1674     }
1675 }
1676
1677 declare_clippy_lint! {
1678     /// **What it does:** Checks for comparisons where the relation is always either
1679     /// true or false, but where one side has been upcast so that the comparison is
1680     /// necessary. Only integer types are checked.
1681     ///
1682     /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
1683     /// will mistakenly imply that it is possible for `x` to be outside the range of
1684     /// `u8`.
1685     ///
1686     /// **Known problems:**
1687     /// https://github.com/rust-lang/rust-clippy/issues/886
1688     ///
1689     /// **Example:**
1690     /// ```rust
1691     /// let x : u8 = ...; (x as u32) > 300
1692     /// ```
1693     pub INVALID_UPCAST_COMPARISONS,
1694     pedantic,
1695     "a comparison involving an upcast which is always true or false"
1696 }
1697
1698 declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
1699
1700 #[derive(Copy, Clone, Debug, Eq)]
1701 enum FullInt {
1702     S(i128),
1703     U(u128),
1704 }
1705
1706 impl FullInt {
1707     #[allow(clippy::cast_sign_loss)]
1708     fn cmp_s_u(s: i128, u: u128) -> Ordering {
1709         if s < 0 {
1710             Ordering::Less
1711         } else if u > (i128::max_value() as u128) {
1712             Ordering::Greater
1713         } else {
1714             (s as u128).cmp(&u)
1715         }
1716     }
1717 }
1718
1719 impl PartialEq for FullInt {
1720     fn eq(&self, other: &Self) -> bool {
1721         self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal
1722     }
1723 }
1724
1725 impl PartialOrd for FullInt {
1726     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1727         Some(match (self, other) {
1728             (&Self::S(s), &Self::S(o)) => s.cmp(&o),
1729             (&Self::U(s), &Self::U(o)) => s.cmp(&o),
1730             (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
1731             (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
1732         })
1733     }
1734 }
1735 impl Ord for FullInt {
1736     fn cmp(&self, other: &Self) -> Ordering {
1737         self.partial_cmp(other)
1738             .expect("partial_cmp for FullInt can never return None")
1739     }
1740 }
1741
1742 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<(FullInt, FullInt)> {
1743     use std::*;
1744
1745     if let ExprKind::Cast(ref cast_exp, _) = expr.node {
1746         let pre_cast_ty = cx.tables.expr_ty(cast_exp);
1747         let cast_ty = cx.tables.expr_ty(expr);
1748         // if it's a cast from i32 to u32 wrapping will invalidate all these checks
1749         if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
1750             return None;
1751         }
1752         match pre_cast_ty.sty {
1753             ty::Int(int_ty) => Some(match int_ty {
1754                 IntTy::I8 => (
1755                     FullInt::S(i128::from(i8::min_value())),
1756                     FullInt::S(i128::from(i8::max_value())),
1757                 ),
1758                 IntTy::I16 => (
1759                     FullInt::S(i128::from(i16::min_value())),
1760                     FullInt::S(i128::from(i16::max_value())),
1761                 ),
1762                 IntTy::I32 => (
1763                     FullInt::S(i128::from(i32::min_value())),
1764                     FullInt::S(i128::from(i32::max_value())),
1765                 ),
1766                 IntTy::I64 => (
1767                     FullInt::S(i128::from(i64::min_value())),
1768                     FullInt::S(i128::from(i64::max_value())),
1769                 ),
1770                 IntTy::I128 => (FullInt::S(i128::min_value()), FullInt::S(i128::max_value())),
1771                 IntTy::Isize => (
1772                     FullInt::S(isize::min_value() as i128),
1773                     FullInt::S(isize::max_value() as i128),
1774                 ),
1775             }),
1776             ty::Uint(uint_ty) => Some(match uint_ty {
1777                 UintTy::U8 => (
1778                     FullInt::U(u128::from(u8::min_value())),
1779                     FullInt::U(u128::from(u8::max_value())),
1780                 ),
1781                 UintTy::U16 => (
1782                     FullInt::U(u128::from(u16::min_value())),
1783                     FullInt::U(u128::from(u16::max_value())),
1784                 ),
1785                 UintTy::U32 => (
1786                     FullInt::U(u128::from(u32::min_value())),
1787                     FullInt::U(u128::from(u32::max_value())),
1788                 ),
1789                 UintTy::U64 => (
1790                     FullInt::U(u128::from(u64::min_value())),
1791                     FullInt::U(u128::from(u64::max_value())),
1792                 ),
1793                 UintTy::U128 => (FullInt::U(u128::min_value()), FullInt::U(u128::max_value())),
1794                 UintTy::Usize => (
1795                     FullInt::U(usize::min_value() as u128),
1796                     FullInt::U(usize::max_value() as u128),
1797                 ),
1798             }),
1799             _ => None,
1800         }
1801     } else {
1802         None
1803     }
1804 }
1805
1806 fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option<FullInt> {
1807     let val = constant(cx, cx.tables, expr)?.0;
1808     if let Constant::Int(const_int) = val {
1809         match cx.tables.expr_ty(expr).sty {
1810             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
1811             ty::Uint(_) => Some(FullInt::U(const_int)),
1812             _ => None,
1813         }
1814     } else {
1815         None
1816     }
1817 }
1818
1819 fn err_upcast_comparison(cx: &LateContext<'_, '_>, span: Span, expr: &Expr, always: bool) {
1820     if let ExprKind::Cast(ref cast_val, _) = expr.node {
1821         span_lint(
1822             cx,
1823             INVALID_UPCAST_COMPARISONS,
1824             span,
1825             &format!(
1826                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
1827                 snippet(cx, cast_val.span, "the expression"),
1828                 if always { "true" } else { "false" },
1829             ),
1830         );
1831     }
1832 }
1833
1834 fn upcast_comparison_bounds_err<'a, 'tcx>(
1835     cx: &LateContext<'a, 'tcx>,
1836     span: Span,
1837     rel: comparisons::Rel,
1838     lhs_bounds: Option<(FullInt, FullInt)>,
1839     lhs: &'tcx Expr,
1840     rhs: &'tcx Expr,
1841     invert: bool,
1842 ) {
1843     use crate::utils::comparisons::*;
1844
1845     if let Some((lb, ub)) = lhs_bounds {
1846         if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
1847             if rel == Rel::Eq || rel == Rel::Ne {
1848                 if norm_rhs_val < lb || norm_rhs_val > ub {
1849                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
1850                 }
1851             } else if match rel {
1852                 Rel::Lt => {
1853                     if invert {
1854                         norm_rhs_val < lb
1855                     } else {
1856                         ub < norm_rhs_val
1857                     }
1858                 },
1859                 Rel::Le => {
1860                     if invert {
1861                         norm_rhs_val <= lb
1862                     } else {
1863                         ub <= norm_rhs_val
1864                     }
1865                 },
1866                 Rel::Eq | Rel::Ne => unreachable!(),
1867             } {
1868                 err_upcast_comparison(cx, span, lhs, true)
1869             } else if match rel {
1870                 Rel::Lt => {
1871                     if invert {
1872                         norm_rhs_val >= ub
1873                     } else {
1874                         lb >= norm_rhs_val
1875                     }
1876                 },
1877                 Rel::Le => {
1878                     if invert {
1879                         norm_rhs_val > ub
1880                     } else {
1881                         lb > norm_rhs_val
1882                     }
1883                 },
1884                 Rel::Eq | Rel::Ne => unreachable!(),
1885             } {
1886                 err_upcast_comparison(cx, span, lhs, false)
1887             }
1888         }
1889     }
1890 }
1891
1892 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidUpcastComparisons {
1893     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
1894         if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.node {
1895             let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
1896             let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
1897                 val
1898             } else {
1899                 return;
1900             };
1901
1902             let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
1903             let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
1904
1905             upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
1906             upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
1907         }
1908     }
1909 }
1910
1911 declare_clippy_lint! {
1912     /// **What it does:** Checks for public `impl` or `fn` missing generalization
1913     /// over different hashers and implicitly defaulting to the default hashing
1914     /// algorithm (SipHash).
1915     ///
1916     /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
1917     /// used with them.
1918     ///
1919     /// **Known problems:** Suggestions for replacing constructors can contain
1920     /// false-positives. Also applying suggestions can require modification of other
1921     /// pieces of code, possibly including external crates.
1922     ///
1923     /// **Example:**
1924     /// ```rust
1925     /// # use std::collections::HashMap;
1926     /// # use std::hash::Hash;
1927     /// # trait Serialize {};
1928     /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
1929     ///
1930     /// pub fn foo(map: &mut HashMap<i32, i32>) { }
1931     /// ```
1932     pub IMPLICIT_HASHER,
1933     style,
1934     "missing generalization over different hashers"
1935 }
1936
1937 declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
1938
1939 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher {
1940     #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
1941     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
1942         use syntax_pos::BytePos;
1943
1944         fn suggestion<'a, 'tcx>(
1945             cx: &LateContext<'a, 'tcx>,
1946             db: &mut DiagnosticBuilder<'_>,
1947             generics_span: Span,
1948             generics_suggestion_span: Span,
1949             target: &ImplicitHasherType<'_>,
1950             vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
1951         ) {
1952             let generics_snip = snippet(cx, generics_span, "");
1953             // trim `<` `>`
1954             let generics_snip = if generics_snip.is_empty() {
1955                 ""
1956             } else {
1957                 &generics_snip[1..generics_snip.len() - 1]
1958             };
1959
1960             multispan_sugg(
1961                 db,
1962                 "consider adding a type parameter".to_string(),
1963                 vec![
1964                     (
1965                         generics_suggestion_span,
1966                         format!(
1967                             "<{}{}S: ::std::hash::BuildHasher{}>",
1968                             generics_snip,
1969                             if generics_snip.is_empty() { "" } else { ", " },
1970                             if vis.suggestions.is_empty() {
1971                                 ""
1972                             } else {
1973                                 // request users to add `Default` bound so that generic constructors can be used
1974                                 " + Default"
1975                             },
1976                         ),
1977                     ),
1978                     (
1979                         target.span(),
1980                         format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
1981                     ),
1982                 ],
1983             );
1984
1985             if !vis.suggestions.is_empty() {
1986                 multispan_sugg(db, "...and use generic constructor".into(), vis.suggestions);
1987             }
1988         }
1989
1990         if !cx.access_levels.is_exported(item.hir_id) {
1991             return;
1992         }
1993
1994         match item.node {
1995             ItemKind::Impl(_, _, _, ref generics, _, ref ty, ref items) => {
1996                 let mut vis = ImplicitHasherTypeVisitor::new(cx);
1997                 vis.visit_ty(ty);
1998
1999                 for target in &vis.found {
2000                     if differing_macro_contexts(item.span, target.span()) {
2001                         return;
2002                     }
2003
2004                     let generics_suggestion_span = generics.span.substitute_dummy({
2005                         let pos = snippet_opt(cx, item.span.until(target.span()))
2006                             .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
2007                         if let Some(pos) = pos {
2008                             Span::new(pos, pos, item.span.data().ctxt)
2009                         } else {
2010                             return;
2011                         }
2012                     });
2013
2014                     let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
2015                     for item in items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
2016                         ctr_vis.visit_impl_item(item);
2017                     }
2018
2019                     span_lint_and_then(
2020                         cx,
2021                         IMPLICIT_HASHER,
2022                         target.span(),
2023                         &format!(
2024                             "impl for `{}` should be generalized over different hashers",
2025                             target.type_name()
2026                         ),
2027                         move |db| {
2028                             suggestion(cx, db, generics.span, generics_suggestion_span, target, ctr_vis);
2029                         },
2030                     );
2031                 }
2032             },
2033             ItemKind::Fn(ref decl, .., ref generics, body_id) => {
2034                 let body = cx.tcx.hir().body(body_id);
2035
2036                 for ty in &decl.inputs {
2037                     let mut vis = ImplicitHasherTypeVisitor::new(cx);
2038                     vis.visit_ty(ty);
2039
2040                     for target in &vis.found {
2041                         if in_external_macro(cx.sess(), generics.span) {
2042                             continue;
2043                         }
2044                         let generics_suggestion_span = generics.span.substitute_dummy({
2045                             let pos = snippet_opt(cx, item.span.until(body.arguments[0].pat.span))
2046                                 .and_then(|snip| {
2047                                     let i = snip.find("fn")?;
2048                                     Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
2049                                 })
2050                                 .expect("failed to create span for type parameters");
2051                             Span::new(pos, pos, item.span.data().ctxt)
2052                         });
2053
2054                         let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
2055                         ctr_vis.visit_body(body);
2056
2057                         span_lint_and_then(
2058                             cx,
2059                             IMPLICIT_HASHER,
2060                             target.span(),
2061                             &format!(
2062                                 "parameter of type `{}` should be generalized over different hashers",
2063                                 target.type_name()
2064                             ),
2065                             move |db| {
2066                                 suggestion(cx, db, generics.span, generics_suggestion_span, target, ctr_vis);
2067                             },
2068                         );
2069                     }
2070                 }
2071             },
2072             _ => {},
2073         }
2074     }
2075 }
2076
2077 enum ImplicitHasherType<'tcx> {
2078     HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
2079     HashSet(Span, Ty<'tcx>, Cow<'static, str>),
2080 }
2081
2082 impl<'tcx> ImplicitHasherType<'tcx> {
2083     /// Checks that `ty` is a target type without a BuildHasher.
2084     fn new<'a>(cx: &LateContext<'a, 'tcx>, hir_ty: &hir::Ty) -> Option<Self> {
2085         if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.node {
2086             let params: Vec<_> = path
2087                 .segments
2088                 .last()
2089                 .as_ref()?
2090                 .args
2091                 .as_ref()?
2092                 .args
2093                 .iter()
2094                 .filter_map(|arg| match arg {
2095                     GenericArg::Type(ty) => Some(ty),
2096                     _ => None,
2097                 })
2098                 .collect();
2099             let params_len = params.len();
2100
2101             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
2102
2103             if match_path(path, &paths::HASHMAP) && params_len == 2 {
2104                 Some(ImplicitHasherType::HashMap(
2105                     hir_ty.span,
2106                     ty,
2107                     snippet(cx, params[0].span, "K"),
2108                     snippet(cx, params[1].span, "V"),
2109                 ))
2110             } else if match_path(path, &paths::HASHSET) && params_len == 1 {
2111                 Some(ImplicitHasherType::HashSet(
2112                     hir_ty.span,
2113                     ty,
2114                     snippet(cx, params[0].span, "T"),
2115                 ))
2116             } else {
2117                 None
2118             }
2119         } else {
2120             None
2121         }
2122     }
2123
2124     fn type_name(&self) -> &'static str {
2125         match *self {
2126             ImplicitHasherType::HashMap(..) => "HashMap",
2127             ImplicitHasherType::HashSet(..) => "HashSet",
2128         }
2129     }
2130
2131     fn type_arguments(&self) -> String {
2132         match *self {
2133             ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
2134             ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
2135         }
2136     }
2137
2138     fn ty(&self) -> Ty<'tcx> {
2139         match *self {
2140             ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
2141         }
2142     }
2143
2144     fn span(&self) -> Span {
2145         match *self {
2146             ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
2147         }
2148     }
2149 }
2150
2151 struct ImplicitHasherTypeVisitor<'a, 'tcx> {
2152     cx: &'a LateContext<'a, 'tcx>,
2153     found: Vec<ImplicitHasherType<'tcx>>,
2154 }
2155
2156 impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
2157     fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
2158         Self { cx, found: vec![] }
2159     }
2160 }
2161
2162 impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
2163     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
2164         if let Some(target) = ImplicitHasherType::new(self.cx, t) {
2165             self.found.push(target);
2166         }
2167
2168         walk_ty(self, t);
2169     }
2170
2171     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
2172         NestedVisitorMap::None
2173     }
2174 }
2175
2176 /// Looks for default-hasher-dependent constructors like `HashMap::new`.
2177 struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
2178     cx: &'a LateContext<'a, 'tcx>,
2179     body: &'a TypeckTables<'tcx>,
2180     target: &'b ImplicitHasherType<'tcx>,
2181     suggestions: BTreeMap<Span, String>,
2182 }
2183
2184 impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
2185     fn new(cx: &'a LateContext<'a, 'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
2186         Self {
2187             cx,
2188             body: cx.tables,
2189             target,
2190             suggestions: BTreeMap::new(),
2191         }
2192     }
2193 }
2194
2195 impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
2196     fn visit_body(&mut self, body: &'tcx Body) {
2197         let prev_body = self.body;
2198         self.body = self.cx.tcx.body_tables(body.id());
2199         walk_body(self, body);
2200         self.body = prev_body;
2201     }
2202
2203     fn visit_expr(&mut self, e: &'tcx Expr) {
2204         if_chain! {
2205             if let ExprKind::Call(ref fun, ref args) = e.node;
2206             if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.node;
2207             if let TyKind::Path(QPath::Resolved(None, ref ty_path)) = ty.node;
2208             then {
2209                 if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) {
2210                     return;
2211                 }
2212
2213                 if match_path(ty_path, &paths::HASHMAP) {
2214                     if method.ident.name == sym!(new) {
2215                         self.suggestions
2216                             .insert(e.span, "HashMap::default()".to_string());
2217                     } else if method.ident.name == sym!(with_capacity) {
2218                         self.suggestions.insert(
2219                             e.span,
2220                             format!(
2221                                 "HashMap::with_capacity_and_hasher({}, Default::default())",
2222                                 snippet(self.cx, args[0].span, "capacity"),
2223                             ),
2224                         );
2225                     }
2226                 } else if match_path(ty_path, &paths::HASHSET) {
2227                     if method.ident.name == sym!(new) {
2228                         self.suggestions
2229                             .insert(e.span, "HashSet::default()".to_string());
2230                     } else if method.ident.name == sym!(with_capacity) {
2231                         self.suggestions.insert(
2232                             e.span,
2233                             format!(
2234                                 "HashSet::with_capacity_and_hasher({}, Default::default())",
2235                                 snippet(self.cx, args[0].span, "capacity"),
2236                             ),
2237                         );
2238                     }
2239                 }
2240             }
2241         }
2242
2243         walk_expr(self, e);
2244     }
2245
2246     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
2247         NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
2248     }
2249 }
2250
2251 declare_clippy_lint! {
2252     /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
2253     ///
2254     /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
2255     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
2256     /// mutable.
2257     ///
2258     /// **Known problems:** None.
2259     ///
2260     /// **Example:**
2261     /// ```rust,ignore
2262     /// fn x(r: &i32) {
2263     ///     unsafe {
2264     ///         *(r as *const _ as *mut _) += 1;
2265     ///     }
2266     /// }
2267     /// ```
2268     ///
2269     /// Instead consider using interior mutability types.
2270     ///
2271     /// ```rust
2272     /// use std::cell::UnsafeCell;
2273     ///
2274     /// fn x(r: &UnsafeCell<i32>) {
2275     ///     unsafe {
2276     ///         *r.get() += 1;
2277     ///     }
2278     /// }
2279     /// ```
2280     pub CAST_REF_TO_MUT,
2281     correctness,
2282     "a cast of reference to a mutable pointer"
2283 }
2284
2285 declare_lint_pass!(RefToMut => [CAST_REF_TO_MUT]);
2286
2287 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RefToMut {
2288     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
2289         if_chain! {
2290             if let ExprKind::Unary(UnOp::UnDeref, e) = &expr.node;
2291             if let ExprKind::Cast(e, t) = &e.node;
2292             if let TyKind::Ptr(MutTy { mutbl: Mutability::MutMutable, .. }) = t.node;
2293             if let ExprKind::Cast(e, t) = &e.node;
2294             if let TyKind::Ptr(MutTy { mutbl: Mutability::MutImmutable, .. }) = t.node;
2295             if let ty::Ref(..) = cx.tables.node_type(e.hir_id).sty;
2296             then {
2297                 span_lint(
2298                     cx,
2299                     CAST_REF_TO_MUT,
2300                     expr.span,
2301                     "casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell",
2302                 );
2303             }
2304         }
2305     }
2306 }