]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/types.rs
Merge pull request #990 from Manishearth/rustfmt
[rust.git] / clippy_lints / src / types.rs
1 use reexport::*;
2 use rustc::hir::*;
3 use rustc::hir::intravisit::{FnKind, Visitor, walk_ty};
4 use rustc::lint::*;
5 use rustc::ty;
6 use std::cmp::Ordering;
7 use syntax::ast::{IntTy, UintTy, FloatTy};
8 use syntax::codemap::Span;
9 use utils::{comparisons, in_external_macro, in_macro, is_from_for_desugar, match_def_path, snippet,
10             span_help_and_lint, span_lint};
11 use utils::paths;
12
13 /// Handles all the linting of funky types
14 #[allow(missing_copy_implementations)]
15 pub struct TypePass;
16
17 /// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code.
18 ///
19 /// **Why is this bad?** `Vec` already keeps its contents in a separate area on the heap. So if you `Box` it, you just add another level of indirection without any benefit whatsoever.
20 ///
21 /// **Known problems:** None
22 ///
23 /// **Example:** `struct X { values: Box<Vec<Foo>> }`
24 declare_lint! {
25     pub BOX_VEC, Warn,
26     "usage of `Box<Vec<T>>`, vector elements are already on the heap"
27 }
28
29 /// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`).
30 ///
31 /// **Why is this bad?** Gankro says:
32 ///
33 /// >The TL;DR of `LinkedList` is that it's built on a massive amount of pointers and indirection. It wastes memory, it has terrible cache locality, and is all-around slow. `RingBuf`, while "only" amortized for push/pop, should be faster in the general case for almost every possible workload, and isn't even amortized at all if you can predict the capacity you need.
34 /// >
35 /// > `LinkedList`s are only really good if you're doing a lot of merging or splitting of lists. This is because they can just mangle some pointers instead of actually copying the data. Even if you're doing a lot of insertion in the middle of the list, `RingBuf` can still be better because of how expensive it is to seek to the middle of a `LinkedList`.
36 ///
37 /// **Known problems:** False positives – the instances where using a `LinkedList` makes sense are few and far between, but they can still happen.
38 ///
39 /// **Example:** `let x = LinkedList::new();`
40 declare_lint! {
41     pub LINKEDLIST, Warn,
42     "usage of LinkedList, usually a vector is faster, or a more specialized data \
43      structure like a VecDeque"
44 }
45
46 impl LintPass for TypePass {
47     fn get_lints(&self) -> LintArray {
48         lint_array!(BOX_VEC, LINKEDLIST)
49     }
50 }
51
52 impl LateLintPass for TypePass {
53     fn check_ty(&mut self, cx: &LateContext, ast_ty: &Ty) {
54         if in_macro(cx, ast_ty.span) {
55             return;
56         }
57         if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) {
58             if let def::Def::Struct(..) = did.full_def() {
59                 if Some(did.def_id()) == cx.tcx.lang_items.owned_box() {
60                     if_let_chain! {[
61                         let TyPath(_, ref path) = ast_ty.node,
62                         let Some(ref last) = path.segments.last(),
63                         let PathParameters::AngleBracketedParameters(ref ag) = last.parameters,
64                         let Some(ref vec) = ag.types.get(0),
65                         let Some(did) = cx.tcx.def_map.borrow().get(&vec.id),
66                         let def::Def::Struct(..) = did.full_def(),
67                         match_def_path(cx, did.def_id(), &paths::VEC),
68                     ], {
69                         span_help_and_lint(cx,
70                                            BOX_VEC,
71                                            ast_ty.span,
72                                            "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
73                                            "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
74                     }}
75                 } else if match_def_path(cx, did.def_id(), &paths::LINKED_LIST) {
76                     span_help_and_lint(cx,
77                                        LINKEDLIST,
78                                        ast_ty.span,
79                                        "I see you're using a LinkedList! Perhaps you meant some other data structure?",
80                                        "a VecDeque might work");
81                 }
82             }
83         }
84     }
85 }
86
87 #[allow(missing_copy_implementations)]
88 pub struct LetPass;
89
90 /// **What it does:** This lint checks for binding a unit value.
91 ///
92 /// **Why is this bad?** A unit value cannot usefully be used anywhere. So binding one is kind of pointless.
93 ///
94 /// **Known problems:** None
95 ///
96 /// **Example:** `let x = { 1; };`
97 declare_lint! {
98     pub LET_UNIT_VALUE, Warn,
99     "creating a let binding to a value of unit type, which usually can't be used afterwards"
100 }
101
102 fn check_let_unit(cx: &LateContext, decl: &Decl) {
103     if let DeclLocal(ref local) = decl.node {
104         let bindtype = &cx.tcx.pat_ty(&local.pat).sty;
105         if *bindtype == ty::TyTuple(&[]) {
106             if in_external_macro(cx, decl.span) || in_macro(cx, local.pat.span) {
107                 return;
108             }
109             if is_from_for_desugar(decl) {
110                 return;
111             }
112             span_lint(cx,
113                       LET_UNIT_VALUE,
114                       decl.span,
115                       &format!("this let-binding has unit value. Consider omitting `let {} =`",
116                                snippet(cx, local.pat.span, "..")));
117         }
118     }
119 }
120
121 impl LintPass for LetPass {
122     fn get_lints(&self) -> LintArray {
123         lint_array!(LET_UNIT_VALUE)
124     }
125 }
126
127 impl LateLintPass for LetPass {
128     fn check_decl(&mut self, cx: &LateContext, decl: &Decl) {
129         check_let_unit(cx, decl)
130     }
131 }
132
133 /// **What it does:** This lint checks for comparisons to unit.
134 ///
135 /// **Why is this bad?** Unit is always equal to itself, and thus is just a clumsily written constant. Mostly this happens when someone accidentally adds semicolons at the end of the operands.
136 ///
137 /// **Known problems:** None
138 ///
139 /// **Example:** `if { foo(); } == { bar(); } { baz(); }` is equal to `{ foo(); bar(); baz(); }`
140 declare_lint! {
141     pub UNIT_CMP, Warn,
142     "comparing unit values (which is always `true` or `false`, respectively)"
143 }
144
145 #[allow(missing_copy_implementations)]
146 pub struct UnitCmp;
147
148 impl LintPass for UnitCmp {
149     fn get_lints(&self) -> LintArray {
150         lint_array!(UNIT_CMP)
151     }
152 }
153
154 impl LateLintPass for UnitCmp {
155     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
156         if in_macro(cx, expr.span) {
157             return;
158         }
159         if let ExprBinary(ref cmp, ref left, _) = expr.node {
160             let op = cmp.node;
161             let sty = &cx.tcx.expr_ty(left).sty;
162             if *sty == ty::TyTuple(&[]) && op.is_comparison() {
163                 let result = match op {
164                     BiEq | BiLe | BiGe => "true",
165                     _ => "false",
166                 };
167                 span_lint(cx,
168                           UNIT_CMP,
169                           expr.span,
170                           &format!("{}-comparison of unit values detected. This will always be {}",
171                                    op.as_str(),
172                                    result));
173             }
174         }
175     }
176 }
177
178 pub struct CastPass;
179
180 /// **What it does:** This lint checks for casts from any numerical to a float type where the receiving type cannot store all values from the original type without rounding errors. This possible rounding is to be expected, so this lint is `Allow` by default.
181 ///
182 /// Basically, this warns on casting any integer with 32 or more bits to `f32` or any 64-bit integer to `f64`.
183 ///
184 /// **Why is this bad?** It's not bad at all. But in some applications it can be helpful to know where precision loss can take place. This lint can help find those places in the code.
185 ///
186 /// **Known problems:** None
187 ///
188 /// **Example:** `let x = u64::MAX; x as f64`
189 declare_lint! {
190     pub CAST_PRECISION_LOSS, Allow,
191     "casts that cause loss of precision, e.g `x as f32` where `x: u64`"
192 }
193
194 /// **What it does:** This lint checks for casts from a signed to an unsigned numerical type. In this case, negative values wrap around to large positive values, which can be quite surprising in practice. However, as the cast works as defined, this lint is `Allow` by default.
195 ///
196 /// **Why is this bad?** Possibly surprising results. You can activate this lint as a one-time check to see where numerical wrapping can arise.
197 ///
198 /// **Known problems:** None
199 ///
200 /// **Example:** `let y : i8 = -1; y as u64` will return 18446744073709551615
201 declare_lint! {
202     pub CAST_SIGN_LOSS, Allow,
203     "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`"
204 }
205
206 /// **What it does:** This lint checks for on casts between numerical types that may truncate large values. This is expected behavior, so the cast is `Allow` by default.
207 ///
208 /// **Why is this bad?** In some problem domains, it is good practice to avoid truncation. This lint can be activated to help assess where additional checks could be beneficial.
209 ///
210 /// **Known problems:** None
211 ///
212 /// **Example:** `fn as_u8(x: u64) -> u8 { x as u8 }`
213 declare_lint! {
214     pub CAST_POSSIBLE_TRUNCATION, Allow,
215     "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
216 }
217
218 /// **What it does:** This lint checks for casts from an unsigned type to a signed type of the same size. Performing such a cast is a 'no-op' for the compiler, i.e. nothing is changed at the bit level, and the binary representation of the value is reinterpreted. This can cause wrapping if the value is too big for the target signed type. However, the cast works as defined, so this lint is `Allow` by default.
219 ///
220 /// **Why is this bad?** While such a cast is not bad in itself, the results can be surprising when this is not the intended behavior, as demonstrated by the example below.
221 ///
222 /// **Known problems:** None
223 ///
224 /// **Example:** `u32::MAX as i32` will yield a value of `-1`.
225 declare_lint! {
226     pub CAST_POSSIBLE_WRAP, Allow,
227     "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`"
228 }
229
230 /// Returns the size in bits of an integral type.
231 /// Will return 0 if the type is not an int or uint variant
232 fn int_ty_to_nbits(typ: &ty::TyS) -> usize {
233     let n = match typ.sty {
234         ty::TyInt(i) => 4 << (i as usize),
235         ty::TyUint(u) => 4 << (u as usize),
236         _ => 0,
237     };
238     // n == 4 is the usize/isize case
239     if n == 4 {
240         ::std::mem::size_of::<usize>() * 8
241     } else {
242         n
243     }
244 }
245
246 fn is_isize_or_usize(typ: &ty::TyS) -> bool {
247     match typ.sty {
248         ty::TyInt(IntTy::Is) |
249         ty::TyUint(UintTy::Us) => true,
250         _ => false,
251     }
252 }
253
254 fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to_f64: bool) {
255     let mantissa_nbits = if cast_to_f64 {
256         52
257     } else {
258         23
259     };
260     let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
261     let arch_dependent_str = "on targets with 64-bit wide pointers ";
262     let from_nbits_str = if arch_dependent {
263         "64".to_owned()
264     } else if is_isize_or_usize(cast_from) {
265         "32 or 64".to_owned()
266     } else {
267         int_ty_to_nbits(cast_from).to_string()
268     };
269     span_lint(cx,
270               CAST_PRECISION_LOSS,
271               expr.span,
272               &format!("casting {0} to {1} causes a loss of precision {2}({0} is {3} bits wide, but {1}'s mantissa \
273                         is only {4} bits wide)",
274                        cast_from,
275                        if cast_to_f64 {
276                            "f64"
277                        } else {
278                            "f32"
279                        },
280                        if arch_dependent {
281                            arch_dependent_str
282                        } else {
283                            ""
284                        },
285                        from_nbits_str,
286                        mantissa_nbits));
287 }
288
289 enum ArchSuffix {
290     _32,
291     _64,
292     None,
293 }
294
295 fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) {
296     let arch_64_suffix = " on targets with 64-bit wide pointers";
297     let arch_32_suffix = " on targets with 32-bit wide pointers";
298     let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
299     let (from_nbits, to_nbits) = (int_ty_to_nbits(cast_from), int_ty_to_nbits(cast_to));
300     let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from),
301                                                                               is_isize_or_usize(cast_to)) {
302         (true, true) | (false, false) => {
303             (to_nbits < from_nbits,
304              ArchSuffix::None,
305              to_nbits == from_nbits && cast_unsigned_to_signed,
306              ArchSuffix::None)
307         }
308         (true, false) => {
309             (to_nbits <= 32,
310              if to_nbits == 32 {
311                 ArchSuffix::_64
312             } else {
313                 ArchSuffix::None
314             },
315              to_nbits <= 32 && cast_unsigned_to_signed,
316              ArchSuffix::_32)
317         }
318         (false, true) => {
319             (from_nbits == 64,
320              ArchSuffix::_32,
321              cast_unsigned_to_signed,
322              if from_nbits == 64 {
323                 ArchSuffix::_64
324             } else {
325                 ArchSuffix::_32
326             })
327         }
328     };
329     if span_truncation {
330         span_lint(cx,
331                   CAST_POSSIBLE_TRUNCATION,
332                   expr.span,
333                   &format!("casting {} to {} may truncate the value{}",
334                            cast_from,
335                            cast_to,
336                            match suffix_truncation {
337                                ArchSuffix::_32 => arch_32_suffix,
338                                ArchSuffix::_64 => arch_64_suffix,
339                                ArchSuffix::None => "",
340                            }));
341     }
342     if span_wrap {
343         span_lint(cx,
344                   CAST_POSSIBLE_WRAP,
345                   expr.span,
346                   &format!("casting {} to {} may wrap around the value{}",
347                            cast_from,
348                            cast_to,
349                            match suffix_wrap {
350                                ArchSuffix::_32 => arch_32_suffix,
351                                ArchSuffix::_64 => arch_64_suffix,
352                                ArchSuffix::None => "",
353                            }));
354     }
355 }
356
357 impl LintPass for CastPass {
358     fn get_lints(&self) -> LintArray {
359         lint_array!(CAST_PRECISION_LOSS,
360                     CAST_SIGN_LOSS,
361                     CAST_POSSIBLE_TRUNCATION,
362                     CAST_POSSIBLE_WRAP)
363     }
364 }
365
366 impl LateLintPass for CastPass {
367     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
368         if let ExprCast(ref ex, _) = expr.node {
369             let (cast_from, cast_to) = (cx.tcx.expr_ty(ex), cx.tcx.expr_ty(expr));
370             if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) {
371                 match (cast_from.is_integral(), cast_to.is_integral()) {
372                     (true, false) => {
373                         let from_nbits = int_ty_to_nbits(cast_from);
374                         let to_nbits = if let ty::TyFloat(FloatTy::F32) = cast_to.sty {
375                             32
376                         } else {
377                             64
378                         };
379                         if is_isize_or_usize(cast_from) || from_nbits >= to_nbits {
380                             span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64);
381                         }
382                     }
383                     (false, true) => {
384                         span_lint(cx,
385                                   CAST_POSSIBLE_TRUNCATION,
386                                   expr.span,
387                                   &format!("casting {} to {} may truncate the value", cast_from, cast_to));
388                         if !cast_to.is_signed() {
389                             span_lint(cx,
390                                       CAST_SIGN_LOSS,
391                                       expr.span,
392                                       &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to));
393                         }
394                     }
395                     (true, true) => {
396                         if cast_from.is_signed() && !cast_to.is_signed() {
397                             span_lint(cx,
398                                       CAST_SIGN_LOSS,
399                                       expr.span,
400                                       &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to));
401                         }
402                         check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
403                     }
404                     (false, false) => {
405                         if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) = (&cast_from.sty,
406                                                                                            &cast_to.sty) {
407                             span_lint(cx,
408                                       CAST_POSSIBLE_TRUNCATION,
409                                       expr.span,
410                                       "casting f64 to f32 may truncate the value");
411                         }
412                     }
413                 }
414             }
415         }
416     }
417 }
418
419 /// **What it does:** This lint checks for types used in structs, parameters and `let` declarations above a certain complexity threshold.
420 ///
421 /// **Why is this bad?** Too complex types make the code less readable. Consider using a `type` definition to simplify them.
422 ///
423 /// **Known problems:** None
424 ///
425 /// **Example:** `struct Foo { inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> }`
426 declare_lint! {
427     pub TYPE_COMPLEXITY, Warn,
428     "usage of very complex types; recommends factoring out parts into `type` definitions"
429 }
430
431 #[allow(missing_copy_implementations)]
432 pub struct TypeComplexityPass {
433     threshold: u64,
434 }
435
436 impl TypeComplexityPass {
437     pub fn new(threshold: u64) -> Self {
438         TypeComplexityPass { threshold: threshold }
439     }
440 }
441
442 impl LintPass for TypeComplexityPass {
443     fn get_lints(&self) -> LintArray {
444         lint_array!(TYPE_COMPLEXITY)
445     }
446 }
447
448 impl LateLintPass for TypeComplexityPass {
449     fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
450         self.check_fndecl(cx, decl);
451     }
452
453     fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) {
454         // enum variants are also struct fields now
455         self.check_type(cx, &field.ty);
456     }
457
458     fn check_item(&mut self, cx: &LateContext, item: &Item) {
459         match item.node {
460             ItemStatic(ref ty, _, _) |
461             ItemConst(ref ty, _) => self.check_type(cx, ty),
462             // functions, enums, structs, impls and traits are covered
463             _ => (),
464         }
465     }
466
467     fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
468         match item.node {
469             ConstTraitItem(ref ty, _) |
470             TypeTraitItem(_, Some(ref ty)) => self.check_type(cx, ty),
471             MethodTraitItem(MethodSig { ref decl, .. }, None) => self.check_fndecl(cx, decl),
472             // methods with default impl are covered by check_fn
473             _ => (),
474         }
475     }
476
477     fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
478         match item.node {
479             ImplItemKind::Const(ref ty, _) |
480             ImplItemKind::Type(ref ty) => self.check_type(cx, ty),
481             // methods are covered by check_fn
482             _ => (),
483         }
484     }
485
486     fn check_local(&mut self, cx: &LateContext, local: &Local) {
487         if let Some(ref ty) = local.ty {
488             self.check_type(cx, ty);
489         }
490     }
491 }
492
493 impl TypeComplexityPass {
494     fn check_fndecl(&self, cx: &LateContext, decl: &FnDecl) {
495         for arg in &decl.inputs {
496             self.check_type(cx, &arg.ty);
497         }
498         if let Return(ref ty) = decl.output {
499             self.check_type(cx, ty);
500         }
501     }
502
503     fn check_type(&self, cx: &LateContext, ty: &Ty) {
504         if in_macro(cx, ty.span) {
505             return;
506         }
507         let score = {
508             let mut visitor = TypeComplexityVisitor {
509                 score: 0,
510                 nest: 1,
511             };
512             visitor.visit_ty(ty);
513             visitor.score
514         };
515
516         if score > self.threshold {
517             span_lint(cx,
518                       TYPE_COMPLEXITY,
519                       ty.span,
520                       "very complex type used. Consider factoring parts into `type` definitions");
521         }
522     }
523 }
524
525 /// Walks a type and assigns a complexity score to it.
526 struct TypeComplexityVisitor {
527     /// total complexity score of the type
528     score: u64,
529     /// current nesting level
530     nest: u64,
531 }
532
533 impl<'v> Visitor<'v> for TypeComplexityVisitor {
534     fn visit_ty(&mut self, ty: &'v Ty) {
535         let (add_score, sub_nest) = match ty.node {
536             // _, &x and *x have only small overhead; don't mess with nesting level
537             TyInfer | TyPtr(..) | TyRptr(..) => (1, 0),
538
539             // the "normal" components of a type: named types, arrays/tuples
540             TyPath(..) |
541             TyVec(..) |
542             TyTup(..) |
543             TyFixedLengthVec(..) => (10 * self.nest, 1),
544
545             // "Sum" of trait bounds
546             TyObjectSum(..) => (20 * self.nest, 0),
547
548             // function types and "for<...>" bring a lot of overhead
549             TyBareFn(..) |
550             TyPolyTraitRef(..) => (50 * self.nest, 1),
551
552             _ => (0, 0),
553         };
554         self.score += add_score;
555         self.nest += sub_nest;
556         walk_ty(self, ty);
557         self.nest -= sub_nest;
558     }
559 }
560
561 /// **What it does:** This lint points out expressions where a character literal is casted to `u8` and suggests using a byte literal instead.
562 ///
563 /// **Why is this bad?** In general, casting values to smaller types is error-prone and should be avoided where possible. In the particular case of converting a character literal to u8, it is easy to avoid by just using a byte literal instead. As an added bonus, `b'a'` is even slightly shorter than `'a' as u8`.
564 ///
565 /// **Known problems:** None
566 ///
567 /// **Example:** `'x' as u8`
568 declare_lint! {
569     pub CHAR_LIT_AS_U8, Warn,
570     "Casting a character literal to u8"
571 }
572
573 pub struct CharLitAsU8;
574
575 impl LintPass for CharLitAsU8 {
576     fn get_lints(&self) -> LintArray {
577         lint_array!(CHAR_LIT_AS_U8)
578     }
579 }
580
581 impl LateLintPass for CharLitAsU8 {
582     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
583         use syntax::ast::{LitKind, UintTy};
584
585         if let ExprCast(ref e, _) = expr.node {
586             if let ExprLit(ref l) = e.node {
587                 if let LitKind::Char(_) = l.node {
588                     if ty::TyUint(UintTy::U8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) {
589                         let msg = "casting character literal to u8. `char`s \
590                                    are 4 bytes wide in rust, so casting to u8 \
591                                    truncates them";
592                         let help = format!("Consider using a byte literal \
593                                             instead:\nb{}",
594                                            snippet(cx, e.span, "'x'"));
595                         span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help);
596                     }
597                 }
598             }
599         }
600     }
601 }
602
603 /// **What it does:** This lint checks for comparisons where one side of the relation is either the minimum or maximum value for its type and warns if it involves a case that is always true or always false. Only integer and boolean types are checked.
604 ///
605 /// **Why is this bad?** An expression like `min <= x` may misleadingly imply that is is possible for `x` to be less than the minimum. Expressions like `max < x` are probably mistakes.
606 ///
607 /// **Known problems:** None
608 ///
609 /// **Example:** `vec.len() <= 0`, `100 > std::i32::MAX`
610 declare_lint! {
611     pub ABSURD_EXTREME_COMPARISONS, Warn,
612     "a comparison involving a maximum or minimum value involves a case that is always \
613     true or always false"
614 }
615
616 pub struct AbsurdExtremeComparisons;
617
618 impl LintPass for AbsurdExtremeComparisons {
619     fn get_lints(&self) -> LintArray {
620         lint_array!(ABSURD_EXTREME_COMPARISONS)
621     }
622 }
623
624 enum ExtremeType {
625     Minimum,
626     Maximum,
627 }
628
629 struct ExtremeExpr<'a> {
630     which: ExtremeType,
631     expr: &'a Expr,
632 }
633
634 enum AbsurdComparisonResult {
635     AlwaysFalse,
636     AlwaysTrue,
637     InequalityImpossible,
638 }
639
640
641
642 fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs: &'a Expr)
643                                 -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> {
644     use types::ExtremeType::*;
645     use types::AbsurdComparisonResult::*;
646     use utils::comparisons::*;
647     type Extr<'a> = ExtremeExpr<'a>;
648
649     let normalized = normalize_comparison(op, lhs, rhs);
650     let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
651         val
652     } else {
653         return None;
654     };
655
656     let lx = detect_extreme_expr(cx, normalized_lhs);
657     let rx = detect_extreme_expr(cx, normalized_rhs);
658
659     Some(match rel {
660         Rel::Lt => {
661             match (lx, rx) {
662                 (Some(l @ Extr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
663                 (_, Some(r @ Extr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
664                 _ => return None,
665             }
666         }
667         Rel::Le => {
668             match (lx, rx) {
669                 (Some(l @ Extr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
670                 (Some(l @ Extr { which: Maximum, .. }), _) => (l, InequalityImpossible), //max <= x
671                 (_, Some(r @ Extr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
672                 (_, Some(r @ Extr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
673                 _ => return None,
674             }
675         }
676         Rel::Ne | Rel::Eq => return None,
677     })
678 }
679
680 fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> {
681     use rustc::middle::const_val::ConstVal::*;
682     use rustc_const_math::*;
683     use rustc_const_eval::EvalHint::ExprTypeChecked;
684     use rustc_const_eval::*;
685     use types::ExtremeType::*;
686
687     let ty = &cx.tcx.expr_ty(expr).sty;
688
689     match *ty {
690         ty::TyBool | ty::TyInt(_) | ty::TyUint(_) => (),
691         _ => return None,
692     };
693
694     let cv = match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) {
695         Ok(val) => val,
696         Err(_) => return None,
697     };
698
699     let which = match (ty, cv) {
700         (&ty::TyBool, Bool(false)) |
701         (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) |
702         (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) |
703         (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) |
704         (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) |
705         (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) |
706         (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) |
707         (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) |
708         (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) |
709         (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) |
710         (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MIN))) |
711         (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MIN))) |
712         (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) => Minimum,
713
714         (&ty::TyBool, Bool(true)) |
715         (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) |
716         (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) |
717         (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) |
718         (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) |
719         (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) |
720         (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) |
721         (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) |
722         (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) |
723         (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) |
724         (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MAX))) |
725         (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MAX))) |
726         (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MAX))) => Maximum,
727
728         _ => return None,
729     };
730     Some(ExtremeExpr {
731         which: which,
732         expr: expr,
733     })
734 }
735
736 impl LateLintPass for AbsurdExtremeComparisons {
737     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
738         use types::ExtremeType::*;
739         use types::AbsurdComparisonResult::*;
740
741         if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node {
742             if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
743                 if !in_macro(cx, expr.span) {
744                     let msg = "this comparison involving the minimum or maximum element for this \
745                                type contains a case that is always true or always false";
746
747                     let conclusion = match result {
748                         AlwaysFalse => "this comparison is always false".to_owned(),
749                         AlwaysTrue => "this comparison is always true".to_owned(),
750                         InequalityImpossible => {
751                             format!("the case where the two sides are not equal never occurs, consider using {} == {} \
752                                      instead",
753                                     snippet(cx, lhs.span, "lhs"),
754                                     snippet(cx, rhs.span, "rhs"))
755                         }
756                     };
757
758                     let help = format!("because {} is the {} value for this type, {}",
759                                        snippet(cx, culprit.expr.span, "x"),
760                                        match culprit.which {
761                                            Minimum => "minimum",
762                                            Maximum => "maximum",
763                                        },
764                                        conclusion);
765
766                     span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help);
767                 }
768             }
769         }
770     }
771 }
772
773 /// **What it does:** This lint checks for comparisons where the relation is always either true or false, but where one side has been upcast so that the comparison is necessary. Only integer types are checked.
774 ///
775 /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300` will mistakenly imply that it is possible for `x` to be outside the range of `u8`.
776 ///
777 /// **Known problems:** https://github.com/Manishearth/rust-clippy/issues/886
778 ///
779 /// **Example:** `let x : u8 = ...; (x as u32) > 300`
780 declare_lint! {
781     pub INVALID_UPCAST_COMPARISONS, Allow,
782     "a comparison involving an upcast which is always true or false"
783 }
784
785 pub struct InvalidUpcastComparisons;
786
787 impl LintPass for InvalidUpcastComparisons {
788     fn get_lints(&self) -> LintArray {
789         lint_array!(INVALID_UPCAST_COMPARISONS)
790     }
791 }
792
793 #[derive(Copy, Clone, Debug, Eq)]
794 enum FullInt {
795     S(i64),
796     U(u64),
797 }
798
799 impl FullInt {
800     #[allow(cast_sign_loss)]
801     fn cmp_s_u(s: i64, u: u64) -> Ordering {
802         if s < 0 {
803             Ordering::Less
804         } else if u > (i64::max_value() as u64) {
805             Ordering::Greater
806         } else {
807             (s as u64).cmp(&u)
808         }
809     }
810 }
811
812 impl PartialEq for FullInt {
813     fn eq(&self, other: &Self) -> bool {
814         self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal
815     }
816 }
817
818 impl PartialOrd for FullInt {
819     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
820         Some(match (self, other) {
821             (&FullInt::S(s), &FullInt::S(o)) => s.cmp(&o),
822             (&FullInt::U(s), &FullInt::U(o)) => s.cmp(&o),
823             (&FullInt::S(s), &FullInt::U(o)) => Self::cmp_s_u(s, o),
824             (&FullInt::U(s), &FullInt::S(o)) => Self::cmp_s_u(o, s).reverse(),
825         })
826     }
827 }
828 impl Ord for FullInt {
829     fn cmp(&self, other: &Self) -> Ordering {
830         self.partial_cmp(other).expect("partial_cmp for FullInt can never return None")
831     }
832 }
833
834
835 fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> {
836     use rustc::ty::TypeVariants::{TyInt, TyUint};
837     use syntax::ast::{IntTy, UintTy};
838     use std::*;
839
840     if let ExprCast(ref cast_exp, _) = expr.node {
841         match cx.tcx.expr_ty(cast_exp).sty {
842             TyInt(int_ty) => {
843                 Some(match int_ty {
844                     IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)),
845                     IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)),
846                     IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)),
847                     IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)),
848                     IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)),
849                 })
850             }
851             TyUint(uint_ty) => {
852                 Some(match uint_ty {
853                     UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)),
854                     UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)),
855                     UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)),
856                     UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)),
857                     UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)),
858                 })
859             }
860             _ => None,
861         }
862     } else {
863         None
864     }
865 }
866
867 fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
868     use rustc::middle::const_val::ConstVal::*;
869     use rustc_const_eval::EvalHint::ExprTypeChecked;
870     use rustc_const_eval::eval_const_expr_partial;
871     use rustc_const_math::ConstInt;
872
873     match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) {
874         Ok(val) => {
875             if let Integral(const_int) = val {
876                 Some(match const_int.erase_type() {
877                     ConstInt::InferSigned(x) => FullInt::S(x as i64),
878                     ConstInt::Infer(x) => FullInt::U(x as u64),
879                     _ => unreachable!(),
880                 })
881             } else {
882                 None
883             }
884         }
885         Err(_) => None,
886     }
887 }
888
889 fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) {
890     if let ExprCast(ref cast_val, _) = expr.node {
891         span_lint(cx,
892                   INVALID_UPCAST_COMPARISONS,
893                   *span,
894                   &format!(
895                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
896                 snippet(cx, cast_val.span, "the expression"),
897                 if always { "true" } else { "false" },
898             ));
899     }
900 }
901
902 fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons::Rel,
903                                 lhs_bounds: Option<(FullInt, FullInt)>, lhs: &Expr, rhs: &Expr, invert: bool) {
904     use utils::comparisons::*;
905
906     if let Some((lb, ub)) = lhs_bounds {
907         if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
908             if rel == Rel::Eq || rel == Rel::Ne {
909                 if norm_rhs_val < lb || norm_rhs_val > ub {
910                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
911                 }
912             } else if match rel {
913                 Rel::Lt => {
914                     if invert {
915                         norm_rhs_val < lb
916                     } else {
917                         ub < norm_rhs_val
918                     }
919                 }
920                 Rel::Le => {
921                     if invert {
922                         norm_rhs_val <= lb
923                     } else {
924                         ub <= norm_rhs_val
925                     }
926                 }
927                 Rel::Eq | Rel::Ne => unreachable!(),
928             } {
929                 err_upcast_comparison(cx, span, lhs, true)
930             } else if match rel {
931                 Rel::Lt => {
932                     if invert {
933                         norm_rhs_val >= ub
934                     } else {
935                         lb >= norm_rhs_val
936                     }
937                 }
938                 Rel::Le => {
939                     if invert {
940                         norm_rhs_val > ub
941                     } else {
942                         lb > norm_rhs_val
943                     }
944                 }
945                 Rel::Eq | Rel::Ne => unreachable!(),
946             } {
947                 err_upcast_comparison(cx, span, lhs, false)
948             }
949         }
950     }
951 }
952
953 impl LateLintPass for InvalidUpcastComparisons {
954     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
955         if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node {
956
957             let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
958             let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
959                 val
960             } else {
961                 return;
962             };
963
964             let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
965             let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
966
967             upcast_comparison_bounds_err(cx, &expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
968             upcast_comparison_bounds_err(cx, &expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
969         }
970     }
971 }