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