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