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