]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/types/mod.rs
Auto merge of #83273 - cjgillot:endecode, r=michaelwoerister
[rust.git] / src / tools / clippy / clippy_lints / src / types / mod.rs
1 #![allow(rustc::default_hash_types)]
2
3 mod borrowed_box;
4 mod box_vec;
5 mod linked_list;
6 mod option_option;
7 mod rc_buffer;
8 mod redundant_allocation;
9 mod utils;
10 mod vec_box;
11
12 use std::borrow::Cow;
13 use std::cmp::Ordering;
14 use std::collections::BTreeMap;
15
16 use if_chain::if_chain;
17 use rustc_errors::{Applicability, DiagnosticBuilder};
18 use rustc_hir as hir;
19 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
20 use rustc_hir::{
21     BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
22     ImplItemKind, Item, ItemKind, Local, MatchSource, MutTy, Node, QPath, Stmt, StmtKind, TraitFn, TraitItem,
23     TraitItemKind, TyKind,
24 };
25 use rustc_lint::{LateContext, LateLintPass, LintContext};
26 use rustc_middle::hir::map::Map;
27 use rustc_middle::lint::in_external_macro;
28 use rustc_middle::ty::{self, IntTy, Ty, TyS, TypeckResults, UintTy};
29 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
30 use rustc_span::hygiene::{ExpnKind, MacroKind};
31 use rustc_span::source_map::Span;
32 use rustc_span::symbol::sym;
33 use rustc_target::abi::LayoutOf;
34 use rustc_target::spec::abi::Abi;
35 use rustc_typeck::hir_ty_to_ty;
36
37 use crate::consts::{constant, Constant};
38 use crate::utils::paths;
39 use crate::utils::{
40     clip, comparisons, differing_macro_contexts, higher, indent_of, int_bits, is_isize_or_usize,
41     is_type_diagnostic_item, match_path, multispan_sugg, reindent_multiline, sext, snippet, snippet_opt,
42     snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_then, unsext,
43 };
44
45 declare_clippy_lint! {
46     /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
47     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
48     ///
49     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
50     /// the heap. So if you `Box` it, you just add another level of indirection
51     /// without any benefit whatsoever.
52     ///
53     /// **Known problems:** None.
54     ///
55     /// **Example:**
56     /// ```rust,ignore
57     /// struct X {
58     ///     values: Box<Vec<Foo>>,
59     /// }
60     /// ```
61     ///
62     /// Better:
63     ///
64     /// ```rust,ignore
65     /// struct X {
66     ///     values: Vec<Foo>,
67     /// }
68     /// ```
69     pub BOX_VEC,
70     perf,
71     "usage of `Box<Vec<T>>`, vector elements are already on the heap"
72 }
73
74 declare_clippy_lint! {
75     /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
76     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
77     ///
78     /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
79     /// the heap. So if you `Box` its contents, you just add another level of indirection.
80     ///
81     /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530),
82     /// 1st comment).
83     ///
84     /// **Example:**
85     /// ```rust
86     /// struct X {
87     ///     values: Vec<Box<i32>>,
88     /// }
89     /// ```
90     ///
91     /// Better:
92     ///
93     /// ```rust
94     /// struct X {
95     ///     values: Vec<i32>,
96     /// }
97     /// ```
98     pub VEC_BOX,
99     complexity,
100     "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
101 }
102
103 declare_clippy_lint! {
104     /// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
105     /// definitions
106     ///
107     /// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
108     /// represents an optional optional value which is logically the same thing as an optional
109     /// value but has an unneeded extra level of wrapping.
110     ///
111     /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
112     /// consider a custom `enum` instead, with clear names for each case.
113     ///
114     /// **Known problems:** None.
115     ///
116     /// **Example**
117     /// ```rust
118     /// fn get_data() -> Option<Option<u32>> {
119     ///     None
120     /// }
121     /// ```
122     ///
123     /// Better:
124     ///
125     /// ```rust
126     /// pub enum Contents {
127     ///     Data(Vec<u8>), // Was Some(Some(Vec<u8>))
128     ///     NotYetFetched, // Was Some(None)
129     ///     None,          // Was None
130     /// }
131     ///
132     /// fn get_data() -> Contents {
133     ///     Contents::None
134     /// }
135     /// ```
136     pub OPTION_OPTION,
137     pedantic,
138     "usage of `Option<Option<T>>`"
139 }
140
141 declare_clippy_lint! {
142     /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
143     /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
144     ///
145     /// **Why is this bad?** Gankro says:
146     ///
147     /// > The TL;DR of `LinkedList` is that it's built on a massive amount of
148     /// pointers and indirection.
149     /// > It wastes memory, it has terrible cache locality, and is all-around slow.
150     /// `RingBuf`, while
151     /// > "only" amortized for push/pop, should be faster in the general case for
152     /// almost every possible
153     /// > workload, and isn't even amortized at all if you can predict the capacity
154     /// you need.
155     /// >
156     /// > `LinkedList`s are only really good if you're doing a lot of merging or
157     /// splitting of lists.
158     /// > This is because they can just mangle some pointers instead of actually
159     /// copying the data. Even
160     /// > if you're doing a lot of insertion in the middle of the list, `RingBuf`
161     /// can still be better
162     /// > because of how expensive it is to seek to the middle of a `LinkedList`.
163     ///
164     /// **Known problems:** False positives – the instances where using a
165     /// `LinkedList` makes sense are few and far between, but they can still happen.
166     ///
167     /// **Example:**
168     /// ```rust
169     /// # use std::collections::LinkedList;
170     /// let x: LinkedList<usize> = LinkedList::new();
171     /// ```
172     pub LINKEDLIST,
173     pedantic,
174     "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`"
175 }
176
177 declare_clippy_lint! {
178     /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
179     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
180     ///
181     /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
182     /// general.
183     ///
184     /// **Known problems:** None.
185     ///
186     /// **Example:**
187     /// ```rust,ignore
188     /// fn foo(bar: &Box<T>) { ... }
189     /// ```
190     ///
191     /// Better:
192     ///
193     /// ```rust,ignore
194     /// fn foo(bar: &T) { ... }
195     /// ```
196     pub BORROWED_BOX,
197     complexity,
198     "a borrow of a boxed type"
199 }
200
201 declare_clippy_lint! {
202     /// **What it does:** Checks for use of redundant allocations anywhere in the code.
203     ///
204     /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
205     /// add an unnecessary level of indirection.
206     ///
207     /// **Known problems:** None.
208     ///
209     /// **Example:**
210     /// ```rust
211     /// # use std::rc::Rc;
212     /// fn foo(bar: Rc<&usize>) {}
213     /// ```
214     ///
215     /// Better:
216     ///
217     /// ```rust
218     /// fn foo(bar: &usize) {}
219     /// ```
220     pub REDUNDANT_ALLOCATION,
221     perf,
222     "redundant allocation"
223 }
224
225 declare_clippy_lint! {
226     /// **What it does:** Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
227     ///
228     /// **Why is this bad?** Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
229     /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
230     ///
231     /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
232     /// works if there are no additional references yet, which usually defeats the purpose of
233     /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
234     /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
235     /// be used.
236     ///
237     /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
238     /// cases where mutation only happens before there are any additional references.
239     ///
240     /// **Example:**
241     /// ```rust,ignore
242     /// # use std::rc::Rc;
243     /// fn foo(interned: Rc<String>) { ... }
244     /// ```
245     ///
246     /// Better:
247     ///
248     /// ```rust,ignore
249     /// fn foo(interned: Rc<str>) { ... }
250     /// ```
251     pub RC_BUFFER,
252     restriction,
253     "shared ownership of a buffer type"
254 }
255
256 pub struct Types {
257     vec_box_size_threshold: u64,
258 }
259
260 impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]);
261
262 impl<'tcx> LateLintPass<'tcx> for Types {
263     fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
264         // Skip trait implementations; see issue #605.
265         if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id)) {
266             if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
267                 return;
268             }
269         }
270
271         self.check_fn_decl(cx, decl);
272     }
273
274     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
275         self.check_ty(cx, &field.ty, false);
276     }
277
278     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
279         match item.kind {
280             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_ty(cx, ty, false),
281             TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, &sig.decl),
282             _ => (),
283         }
284     }
285
286     fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
287         if let Some(ref ty) = local.ty {
288             self.check_ty(cx, ty, true);
289         }
290     }
291 }
292
293 impl Types {
294     pub fn new(vec_box_size_threshold: u64) -> Self {
295         Self { vec_box_size_threshold }
296     }
297
298     fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>) {
299         for input in decl.inputs {
300             self.check_ty(cx, input, false);
301         }
302
303         if let FnRetTy::Return(ref ty) = decl.output {
304             self.check_ty(cx, ty, false);
305         }
306     }
307
308     /// Recursively check for `TypePass` lints in the given type. Stop at the first
309     /// lint found.
310     ///
311     /// The parameter `is_local` distinguishes the context of the type.
312     fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, is_local: bool) {
313         if hir_ty.span.from_expansion() {
314             return;
315         }
316         match hir_ty.kind {
317             TyKind::Path(ref qpath) if !is_local => {
318                 let hir_id = hir_ty.hir_id;
319                 let res = cx.qpath_res(qpath, hir_id);
320                 if let Some(def_id) = res.opt_def_id() {
321                     let mut triggered = false;
322                     triggered |= box_vec::check(cx, hir_ty, qpath, def_id);
323                     triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id);
324                     triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id);
325                     triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold);
326                     triggered |= option_option::check(cx, hir_ty, qpath, def_id);
327                     triggered |= linked_list::check(cx, hir_ty, def_id);
328
329                     if triggered {
330                         return;
331                     }
332                 }
333                 match *qpath {
334                     QPath::Resolved(Some(ref ty), ref p) => {
335                         self.check_ty(cx, ty, is_local);
336                         for ty in p.segments.iter().flat_map(|seg| {
337                             seg.args
338                                 .as_ref()
339                                 .map_or_else(|| [].iter(), |params| params.args.iter())
340                                 .filter_map(|arg| match arg {
341                                     GenericArg::Type(ty) => Some(ty),
342                                     _ => None,
343                                 })
344                         }) {
345                             self.check_ty(cx, ty, is_local);
346                         }
347                     },
348                     QPath::Resolved(None, ref p) => {
349                         for ty in p.segments.iter().flat_map(|seg| {
350                             seg.args
351                                 .as_ref()
352                                 .map_or_else(|| [].iter(), |params| params.args.iter())
353                                 .filter_map(|arg| match arg {
354                                     GenericArg::Type(ty) => Some(ty),
355                                     _ => None,
356                                 })
357                         }) {
358                             self.check_ty(cx, ty, is_local);
359                         }
360                     },
361                     QPath::TypeRelative(ref ty, ref seg) => {
362                         self.check_ty(cx, ty, is_local);
363                         if let Some(ref params) = seg.args {
364                             for ty in params.args.iter().filter_map(|arg| match arg {
365                                 GenericArg::Type(ty) => Some(ty),
366                                 _ => None,
367                             }) {
368                                 self.check_ty(cx, ty, is_local);
369                             }
370                         }
371                     },
372                     QPath::LangItem(..) => {},
373                 }
374             },
375             TyKind::Rptr(ref lt, ref mut_ty) => {
376                 if !borrowed_box::check(cx, hir_ty, lt, mut_ty) {
377                     self.check_ty(cx, &mut_ty.ty, is_local);
378                 }
379             },
380             TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => {
381                 self.check_ty(cx, ty, is_local)
382             },
383             TyKind::Tup(tys) => {
384                 for ty in tys {
385                     self.check_ty(cx, ty, is_local);
386                 }
387             },
388             _ => {},
389         }
390     }
391 }
392
393 declare_clippy_lint! {
394     /// **What it does:** Checks for binding a unit value.
395     ///
396     /// **Why is this bad?** A unit value cannot usefully be used anywhere. So
397     /// binding one is kind of pointless.
398     ///
399     /// **Known problems:** None.
400     ///
401     /// **Example:**
402     /// ```rust
403     /// let x = {
404     ///     1;
405     /// };
406     /// ```
407     pub LET_UNIT_VALUE,
408     pedantic,
409     "creating a `let` binding to a value of unit type, which usually can't be used afterwards"
410 }
411
412 declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]);
413
414 impl<'tcx> LateLintPass<'tcx> for LetUnitValue {
415     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
416         if let StmtKind::Local(ref local) = stmt.kind {
417             if is_unit(cx.typeck_results().pat_ty(&local.pat)) {
418                 if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
419                     return;
420                 }
421                 if higher::is_from_for_desugar(local) {
422                     return;
423                 }
424                 span_lint_and_then(
425                     cx,
426                     LET_UNIT_VALUE,
427                     stmt.span,
428                     "this let-binding has unit value",
429                     |diag| {
430                         if let Some(expr) = &local.init {
431                             let snip = snippet_with_macro_callsite(cx, expr.span, "()");
432                             diag.span_suggestion(
433                                 stmt.span,
434                                 "omit the `let` binding",
435                                 format!("{};", snip),
436                                 Applicability::MachineApplicable, // snippet
437                             );
438                         }
439                     },
440                 );
441             }
442         }
443     }
444 }
445
446 declare_clippy_lint! {
447     /// **What it does:** Checks for comparisons to unit. This includes all binary
448     /// comparisons (like `==` and `<`) and asserts.
449     ///
450     /// **Why is this bad?** Unit is always equal to itself, and thus is just a
451     /// clumsily written constant. Mostly this happens when someone accidentally
452     /// adds semicolons at the end of the operands.
453     ///
454     /// **Known problems:** None.
455     ///
456     /// **Example:**
457     /// ```rust
458     /// # fn foo() {};
459     /// # fn bar() {};
460     /// # fn baz() {};
461     /// if {
462     ///     foo();
463     /// } == {
464     ///     bar();
465     /// } {
466     ///     baz();
467     /// }
468     /// ```
469     /// is equal to
470     /// ```rust
471     /// # fn foo() {};
472     /// # fn bar() {};
473     /// # fn baz() {};
474     /// {
475     ///     foo();
476     ///     bar();
477     ///     baz();
478     /// }
479     /// ```
480     ///
481     /// For asserts:
482     /// ```rust
483     /// # fn foo() {};
484     /// # fn bar() {};
485     /// assert_eq!({ foo(); }, { bar(); });
486     /// ```
487     /// will always succeed
488     pub UNIT_CMP,
489     correctness,
490     "comparing unit values"
491 }
492
493 declare_lint_pass!(UnitCmp => [UNIT_CMP]);
494
495 impl<'tcx> LateLintPass<'tcx> for UnitCmp {
496     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
497         if expr.span.from_expansion() {
498             if let Some(callee) = expr.span.source_callee() {
499                 if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
500                     if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
501                         let op = cmp.node;
502                         if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
503                             let result = match &*symbol.as_str() {
504                                 "assert_eq" | "debug_assert_eq" => "succeed",
505                                 "assert_ne" | "debug_assert_ne" => "fail",
506                                 _ => return,
507                             };
508                             span_lint(
509                                 cx,
510                                 UNIT_CMP,
511                                 expr.span,
512                                 &format!(
513                                     "`{}` of unit values detected. This will always {}",
514                                     symbol.as_str(),
515                                     result
516                                 ),
517                             );
518                         }
519                     }
520                 }
521             }
522             return;
523         }
524         if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
525             let op = cmp.node;
526             if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
527                 let result = match op {
528                     BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
529                     _ => "false",
530                 };
531                 span_lint(
532                     cx,
533                     UNIT_CMP,
534                     expr.span,
535                     &format!(
536                         "{}-comparison of unit values detected. This will always be {}",
537                         op.as_str(),
538                         result
539                     ),
540                 );
541             }
542         }
543     }
544 }
545
546 declare_clippy_lint! {
547     /// **What it does:** Checks for passing a unit value as an argument to a function without using a
548     /// unit literal (`()`).
549     ///
550     /// **Why is this bad?** This is likely the result of an accidental semicolon.
551     ///
552     /// **Known problems:** None.
553     ///
554     /// **Example:**
555     /// ```rust,ignore
556     /// foo({
557     ///     let a = bar();
558     ///     baz(a);
559     /// })
560     /// ```
561     pub UNIT_ARG,
562     complexity,
563     "passing unit to a function"
564 }
565
566 declare_lint_pass!(UnitArg => [UNIT_ARG]);
567
568 impl<'tcx> LateLintPass<'tcx> for UnitArg {
569     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
570         if expr.span.from_expansion() {
571             return;
572         }
573
574         // apparently stuff in the desugaring of `?` can trigger this
575         // so check for that here
576         // only the calls to `Try::from_error` is marked as desugared,
577         // so we need to check both the current Expr and its parent.
578         if is_questionmark_desugar_marked_call(expr) {
579             return;
580         }
581         if_chain! {
582             let map = &cx.tcx.hir();
583             let opt_parent_node = map.find(map.get_parent_node(expr.hir_id));
584             if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
585             if is_questionmark_desugar_marked_call(parent_expr);
586             then {
587                 return;
588             }
589         }
590
591         match expr.kind {
592             ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => {
593                 let args_to_recover = args
594                     .iter()
595                     .filter(|arg| {
596                         if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) {
597                             !matches!(
598                                 &arg.kind,
599                                 ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
600                             )
601                         } else {
602                             false
603                         }
604                     })
605                     .collect::<Vec<_>>();
606                 if !args_to_recover.is_empty() {
607                     lint_unit_args(cx, expr, &args_to_recover);
608                 }
609             },
610             _ => (),
611         }
612     }
613 }
614
615 fn fmt_stmts_and_call(
616     cx: &LateContext<'_>,
617     call_expr: &Expr<'_>,
618     call_snippet: &str,
619     args_snippets: &[impl AsRef<str>],
620     non_empty_block_args_snippets: &[impl AsRef<str>],
621 ) -> String {
622     let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
623     let call_snippet_with_replacements = args_snippets
624         .iter()
625         .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1));
626
627     let mut stmts_and_call = non_empty_block_args_snippets
628         .iter()
629         .map(|it| it.as_ref().to_owned())
630         .collect::<Vec<_>>();
631     stmts_and_call.push(call_snippet_with_replacements);
632     stmts_and_call = stmts_and_call
633         .into_iter()
634         .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned())
635         .collect();
636
637     let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
638     // expr is not in a block statement or result expression position, wrap in a block
639     let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id));
640     if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
641         let block_indent = call_expr_indent + 4;
642         stmts_and_call_snippet =
643             reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();
644         stmts_and_call_snippet = format!(
645             "{{\n{}{}\n{}}}",
646             " ".repeat(block_indent),
647             &stmts_and_call_snippet,
648             " ".repeat(call_expr_indent)
649         );
650     }
651     stmts_and_call_snippet
652 }
653
654 fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
655     let mut applicability = Applicability::MachineApplicable;
656     let (singular, plural) = if args_to_recover.len() > 1 {
657         ("", "s")
658     } else {
659         ("a ", "")
660     };
661     span_lint_and_then(
662         cx,
663         UNIT_ARG,
664         expr.span,
665         &format!("passing {}unit value{} to a function", singular, plural),
666         |db| {
667             let mut or = "";
668             args_to_recover
669                 .iter()
670                 .filter_map(|arg| {
671                     if_chain! {
672                         if let ExprKind::Block(block, _) = arg.kind;
673                         if block.expr.is_none();
674                         if let Some(last_stmt) = block.stmts.iter().last();
675                         if let StmtKind::Semi(last_expr) = last_stmt.kind;
676                         if let Some(snip) = snippet_opt(cx, last_expr.span);
677                         then {
678                             Some((
679                                 last_stmt.span,
680                                 snip,
681                             ))
682                         }
683                         else {
684                             None
685                         }
686                     }
687                 })
688                 .for_each(|(span, sugg)| {
689                     db.span_suggestion(
690                         span,
691                         "remove the semicolon from the last statement in the block",
692                         sugg,
693                         Applicability::MaybeIncorrect,
694                     );
695                     or = "or ";
696                     applicability = Applicability::MaybeIncorrect;
697                 });
698
699             let arg_snippets: Vec<String> = args_to_recover
700                 .iter()
701                 .filter_map(|arg| snippet_opt(cx, arg.span))
702                 .collect();
703             let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover
704                 .iter()
705                 .filter(|arg| !is_empty_block(arg))
706                 .filter_map(|arg| snippet_opt(cx, arg.span))
707                 .collect();
708
709             if let Some(call_snippet) = snippet_opt(cx, expr.span) {
710                 let sugg = fmt_stmts_and_call(
711                     cx,
712                     expr,
713                     &call_snippet,
714                     &arg_snippets,
715                     &arg_snippets_without_empty_blocks,
716                 );
717
718                 if arg_snippets_without_empty_blocks.is_empty() {
719                     db.multipart_suggestion(
720                         &format!("use {}unit literal{} instead", singular, plural),
721                         args_to_recover
722                             .iter()
723                             .map(|arg| (arg.span, "()".to_string()))
724                             .collect::<Vec<_>>(),
725                         applicability,
726                     );
727                 } else {
728                     let plural = arg_snippets_without_empty_blocks.len() > 1;
729                     let empty_or_s = if plural { "s" } else { "" };
730                     let it_or_them = if plural { "them" } else { "it" };
731                     db.span_suggestion(
732                         expr.span,
733                         &format!(
734                             "{}move the expression{} in front of the call and replace {} with the unit literal `()`",
735                             or, empty_or_s, it_or_them
736                         ),
737                         sugg,
738                         applicability,
739                     );
740                 }
741             }
742         },
743     );
744 }
745
746 fn is_empty_block(expr: &Expr<'_>) -> bool {
747     matches!(
748         expr.kind,
749         ExprKind::Block(
750             Block {
751                 stmts: &[],
752                 expr: None,
753                 ..
754             },
755             _,
756         )
757     )
758 }
759
760 fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
761     use rustc_span::hygiene::DesugaringKind;
762     if let ExprKind::Call(ref callee, _) = expr.kind {
763         callee.span.is_desugaring(DesugaringKind::QuestionMark)
764     } else {
765         false
766     }
767 }
768
769 fn is_unit(ty: Ty<'_>) -> bool {
770     matches!(ty.kind(), ty::Tuple(slice) if slice.is_empty())
771 }
772
773 fn is_unit_literal(expr: &Expr<'_>) -> bool {
774     matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty())
775 }
776
777 declare_clippy_lint! {
778     /// **What it does:** Checks for types used in structs, parameters and `let`
779     /// declarations above a certain complexity threshold.
780     ///
781     /// **Why is this bad?** Too complex types make the code less readable. Consider
782     /// using a `type` definition to simplify them.
783     ///
784     /// **Known problems:** None.
785     ///
786     /// **Example:**
787     /// ```rust
788     /// # use std::rc::Rc;
789     /// struct Foo {
790     ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
791     /// }
792     /// ```
793     pub TYPE_COMPLEXITY,
794     complexity,
795     "usage of very complex types that might be better factored into `type` definitions"
796 }
797
798 pub struct TypeComplexity {
799     threshold: u64,
800 }
801
802 impl TypeComplexity {
803     #[must_use]
804     pub fn new(threshold: u64) -> Self {
805         Self { threshold }
806     }
807 }
808
809 impl_lint_pass!(TypeComplexity => [TYPE_COMPLEXITY]);
810
811 impl<'tcx> LateLintPass<'tcx> for TypeComplexity {
812     fn check_fn(
813         &mut self,
814         cx: &LateContext<'tcx>,
815         _: FnKind<'tcx>,
816         decl: &'tcx FnDecl<'_>,
817         _: &'tcx Body<'_>,
818         _: Span,
819         _: HirId,
820     ) {
821         self.check_fndecl(cx, decl);
822     }
823
824     fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'_>) {
825         // enum variants are also struct fields now
826         self.check_type(cx, &field.ty);
827     }
828
829     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
830         match item.kind {
831             ItemKind::Static(ref ty, _, _) | ItemKind::Const(ref ty, _) => self.check_type(cx, ty),
832             // functions, enums, structs, impls and traits are covered
833             _ => (),
834         }
835     }
836
837     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
838         match item.kind {
839             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty),
840             TraitItemKind::Fn(FnSig { ref decl, .. }, TraitFn::Required(_)) => self.check_fndecl(cx, decl),
841             // methods with default impl are covered by check_fn
842             _ => (),
843         }
844     }
845
846     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
847         match item.kind {
848             ImplItemKind::Const(ref ty, _) | ImplItemKind::TyAlias(ref ty) => self.check_type(cx, ty),
849             // methods are covered by check_fn
850             _ => (),
851         }
852     }
853
854     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
855         if let Some(ref ty) = local.ty {
856             self.check_type(cx, ty);
857         }
858     }
859 }
860
861 impl<'tcx> TypeComplexity {
862     fn check_fndecl(&self, cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>) {
863         for arg in decl.inputs {
864             self.check_type(cx, arg);
865         }
866         if let FnRetTy::Return(ref ty) = decl.output {
867             self.check_type(cx, ty);
868         }
869     }
870
871     fn check_type(&self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
872         if ty.span.from_expansion() {
873             return;
874         }
875         let score = {
876             let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 };
877             visitor.visit_ty(ty);
878             visitor.score
879         };
880
881         if score > self.threshold {
882             span_lint(
883                 cx,
884                 TYPE_COMPLEXITY,
885                 ty.span,
886                 "very complex type used. Consider factoring parts into `type` definitions",
887             );
888         }
889     }
890 }
891
892 /// Walks a type and assigns a complexity score to it.
893 struct TypeComplexityVisitor {
894     /// total complexity score of the type
895     score: u64,
896     /// current nesting level
897     nest: u64,
898 }
899
900 impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
901     type Map = Map<'tcx>;
902
903     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
904         let (add_score, sub_nest) = match ty.kind {
905             // _, &x and *x have only small overhead; don't mess with nesting level
906             TyKind::Infer | TyKind::Ptr(..) | TyKind::Rptr(..) => (1, 0),
907
908             // the "normal" components of a type: named types, arrays/tuples
909             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
910
911             // function types bring a lot of overhead
912             TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
913
914             TyKind::TraitObject(ref param_bounds, ..) => {
915                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
916                     bound
917                         .bound_generic_params
918                         .iter()
919                         .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
920                 });
921                 if has_lifetime_parameters {
922                     // complex trait bounds like A<'a, 'b>
923                     (50 * self.nest, 1)
924                 } else {
925                     // simple trait bounds like A + B
926                     (20 * self.nest, 0)
927                 }
928             },
929
930             _ => (0, 0),
931         };
932         self.score += add_score;
933         self.nest += sub_nest;
934         walk_ty(self, ty);
935         self.nest -= sub_nest;
936     }
937     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
938         NestedVisitorMap::None
939     }
940 }
941
942 declare_clippy_lint! {
943     /// **What it does:** Checks for comparisons where one side of the relation is
944     /// either the minimum or maximum value for its type and warns if it involves a
945     /// case that is always true or always false. Only integer and boolean types are
946     /// checked.
947     ///
948     /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
949     /// that it is possible for `x` to be less than the minimum. Expressions like
950     /// `max < x` are probably mistakes.
951     ///
952     /// **Known problems:** For `usize` the size of the current compile target will
953     /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
954     /// a comparison to detect target pointer width will trigger this lint. One can
955     /// use `mem::sizeof` and compare its value or conditional compilation
956     /// attributes
957     /// like `#[cfg(target_pointer_width = "64")] ..` instead.
958     ///
959     /// **Example:**
960     ///
961     /// ```rust
962     /// let vec: Vec<isize> = Vec::new();
963     /// if vec.len() <= 0 {}
964     /// if 100 > i32::MAX {}
965     /// ```
966     pub ABSURD_EXTREME_COMPARISONS,
967     correctness,
968     "a comparison with a maximum or minimum value that is always true or false"
969 }
970
971 declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
972
973 enum ExtremeType {
974     Minimum,
975     Maximum,
976 }
977
978 struct ExtremeExpr<'a> {
979     which: ExtremeType,
980     expr: &'a Expr<'a>,
981 }
982
983 enum AbsurdComparisonResult {
984     AlwaysFalse,
985     AlwaysTrue,
986     InequalityImpossible,
987 }
988
989 fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
990     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
991         let precast_ty = cx.typeck_results().expr_ty(cast_exp);
992         let cast_ty = cx.typeck_results().expr_ty(expr);
993
994         return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
995     }
996
997     false
998 }
999
1000 fn detect_absurd_comparison<'tcx>(
1001     cx: &LateContext<'tcx>,
1002     op: BinOpKind,
1003     lhs: &'tcx Expr<'_>,
1004     rhs: &'tcx Expr<'_>,
1005 ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
1006     use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
1007     use crate::types::ExtremeType::{Maximum, Minimum};
1008     use crate::utils::comparisons::{normalize_comparison, Rel};
1009
1010     // absurd comparison only makes sense on primitive types
1011     // primitive types don't implement comparison operators with each other
1012     if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
1013         return None;
1014     }
1015
1016     // comparisons between fix sized types and target sized types are considered unanalyzable
1017     if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
1018         return None;
1019     }
1020
1021     let (rel, normalized_lhs, normalized_rhs) = normalize_comparison(op, lhs, rhs)?;
1022
1023     let lx = detect_extreme_expr(cx, normalized_lhs);
1024     let rx = detect_extreme_expr(cx, normalized_rhs);
1025
1026     Some(match rel {
1027         Rel::Lt => {
1028             match (lx, rx) {
1029                 (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x
1030                 (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
1031                 _ => return None,
1032             }
1033         },
1034         Rel::Le => {
1035             match (lx, rx) {
1036                 (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
1037                 (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), // max <= x
1038                 (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, InequalityImpossible), // x <= min
1039                 (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
1040                 _ => return None,
1041             }
1042         },
1043         Rel::Ne | Rel::Eq => return None,
1044     })
1045 }
1046
1047 fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
1048     use crate::types::ExtremeType::{Maximum, Minimum};
1049
1050     let ty = cx.typeck_results().expr_ty(expr);
1051
1052     let cv = constant(cx, cx.typeck_results(), expr)?.0;
1053
1054     let which = match (ty.kind(), cv) {
1055         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
1056         (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
1057             Minimum
1058         },
1059
1060         (&ty::Bool, Constant::Bool(true)) => Maximum,
1061         (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
1062             Maximum
1063         },
1064         (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
1065
1066         _ => return None,
1067     };
1068     Some(ExtremeExpr { which, expr })
1069 }
1070
1071 impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons {
1072     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
1073         use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible};
1074         use crate::types::ExtremeType::{Maximum, Minimum};
1075
1076         if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
1077             if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) {
1078                 if !expr.span.from_expansion() {
1079                     let msg = "this comparison involving the minimum or maximum element for this \
1080                                type contains a case that is always true or always false";
1081
1082                     let conclusion = match result {
1083                         AlwaysFalse => "this comparison is always false".to_owned(),
1084                         AlwaysTrue => "this comparison is always true".to_owned(),
1085                         InequalityImpossible => format!(
1086                             "the case where the two sides are not equal never occurs, consider using `{} == {}` \
1087                              instead",
1088                             snippet(cx, lhs.span, "lhs"),
1089                             snippet(cx, rhs.span, "rhs")
1090                         ),
1091                     };
1092
1093                     let help = format!(
1094                         "because `{}` is the {} value for this type, {}",
1095                         snippet(cx, culprit.expr.span, "x"),
1096                         match culprit.which {
1097                             Minimum => "minimum",
1098                             Maximum => "maximum",
1099                         },
1100                         conclusion
1101                     );
1102
1103                     span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
1104                 }
1105             }
1106         }
1107     }
1108 }
1109
1110 declare_clippy_lint! {
1111     /// **What it does:** Checks for comparisons where the relation is always either
1112     /// true or false, but where one side has been upcast so that the comparison is
1113     /// necessary. Only integer types are checked.
1114     ///
1115     /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
1116     /// will mistakenly imply that it is possible for `x` to be outside the range of
1117     /// `u8`.
1118     ///
1119     /// **Known problems:**
1120     /// https://github.com/rust-lang/rust-clippy/issues/886
1121     ///
1122     /// **Example:**
1123     /// ```rust
1124     /// let x: u8 = 1;
1125     /// (x as u32) > 300;
1126     /// ```
1127     pub INVALID_UPCAST_COMPARISONS,
1128     pedantic,
1129     "a comparison involving an upcast which is always true or false"
1130 }
1131
1132 declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
1133
1134 #[derive(Copy, Clone, Debug, Eq)]
1135 enum FullInt {
1136     S(i128),
1137     U(u128),
1138 }
1139
1140 impl FullInt {
1141     #[allow(clippy::cast_sign_loss)]
1142     #[must_use]
1143     fn cmp_s_u(s: i128, u: u128) -> Ordering {
1144         if s < 0 {
1145             Ordering::Less
1146         } else if u > (i128::MAX as u128) {
1147             Ordering::Greater
1148         } else {
1149             (s as u128).cmp(&u)
1150         }
1151     }
1152 }
1153
1154 impl PartialEq for FullInt {
1155     #[must_use]
1156     fn eq(&self, other: &Self) -> bool {
1157         self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
1158     }
1159 }
1160
1161 impl PartialOrd for FullInt {
1162     #[must_use]
1163     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1164         Some(match (self, other) {
1165             (&Self::S(s), &Self::S(o)) => s.cmp(&o),
1166             (&Self::U(s), &Self::U(o)) => s.cmp(&o),
1167             (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
1168             (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
1169         })
1170     }
1171 }
1172
1173 impl Ord for FullInt {
1174     #[must_use]
1175     fn cmp(&self, other: &Self) -> Ordering {
1176         self.partial_cmp(other)
1177             .expect("`partial_cmp` for FullInt can never return `None`")
1178     }
1179 }
1180
1181 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
1182     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
1183         let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
1184         let cast_ty = cx.typeck_results().expr_ty(expr);
1185         // if it's a cast from i32 to u32 wrapping will invalidate all these checks
1186         if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
1187             return None;
1188         }
1189         match pre_cast_ty.kind() {
1190             ty::Int(int_ty) => Some(match int_ty {
1191                 IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
1192                 IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
1193                 IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
1194                 IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
1195                 IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
1196                 IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
1197             }),
1198             ty::Uint(uint_ty) => Some(match uint_ty {
1199                 UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
1200                 UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
1201                 UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
1202                 UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
1203                 UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
1204                 UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
1205             }),
1206             _ => None,
1207         }
1208     } else {
1209         None
1210     }
1211 }
1212
1213 fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
1214     let val = constant(cx, cx.typeck_results(), expr)?.0;
1215     if let Constant::Int(const_int) = val {
1216         match *cx.typeck_results().expr_ty(expr).kind() {
1217             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
1218             ty::Uint(_) => Some(FullInt::U(const_int)),
1219             _ => None,
1220         }
1221     } else {
1222         None
1223     }
1224 }
1225
1226 fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
1227     if let ExprKind::Cast(ref cast_val, _) = expr.kind {
1228         span_lint(
1229             cx,
1230             INVALID_UPCAST_COMPARISONS,
1231             span,
1232             &format!(
1233                 "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
1234                 snippet(cx, cast_val.span, "the expression"),
1235                 if always { "true" } else { "false" },
1236             ),
1237         );
1238     }
1239 }
1240
1241 fn upcast_comparison_bounds_err<'tcx>(
1242     cx: &LateContext<'tcx>,
1243     span: Span,
1244     rel: comparisons::Rel,
1245     lhs_bounds: Option<(FullInt, FullInt)>,
1246     lhs: &'tcx Expr<'_>,
1247     rhs: &'tcx Expr<'_>,
1248     invert: bool,
1249 ) {
1250     use crate::utils::comparisons::Rel;
1251
1252     if let Some((lb, ub)) = lhs_bounds {
1253         if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
1254             if rel == Rel::Eq || rel == Rel::Ne {
1255                 if norm_rhs_val < lb || norm_rhs_val > ub {
1256                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
1257                 }
1258             } else if match rel {
1259                 Rel::Lt => {
1260                     if invert {
1261                         norm_rhs_val < lb
1262                     } else {
1263                         ub < norm_rhs_val
1264                     }
1265                 },
1266                 Rel::Le => {
1267                     if invert {
1268                         norm_rhs_val <= lb
1269                     } else {
1270                         ub <= norm_rhs_val
1271                     }
1272                 },
1273                 Rel::Eq | Rel::Ne => unreachable!(),
1274             } {
1275                 err_upcast_comparison(cx, span, lhs, true)
1276             } else if match rel {
1277                 Rel::Lt => {
1278                     if invert {
1279                         norm_rhs_val >= ub
1280                     } else {
1281                         lb >= norm_rhs_val
1282                     }
1283                 },
1284                 Rel::Le => {
1285                     if invert {
1286                         norm_rhs_val > ub
1287                     } else {
1288                         lb > norm_rhs_val
1289                     }
1290                 },
1291                 Rel::Eq | Rel::Ne => unreachable!(),
1292             } {
1293                 err_upcast_comparison(cx, span, lhs, false)
1294             }
1295         }
1296     }
1297 }
1298
1299 impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
1300     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
1301         if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind {
1302             let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
1303             let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
1304                 val
1305             } else {
1306                 return;
1307             };
1308
1309             let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
1310             let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
1311
1312             upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
1313             upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
1314         }
1315     }
1316 }
1317
1318 declare_clippy_lint! {
1319     /// **What it does:** Checks for public `impl` or `fn` missing generalization
1320     /// over different hashers and implicitly defaulting to the default hashing
1321     /// algorithm (`SipHash`).
1322     ///
1323     /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
1324     /// used with them.
1325     ///
1326     /// **Known problems:** Suggestions for replacing constructors can contain
1327     /// false-positives. Also applying suggestions can require modification of other
1328     /// pieces of code, possibly including external crates.
1329     ///
1330     /// **Example:**
1331     /// ```rust
1332     /// # use std::collections::HashMap;
1333     /// # use std::hash::{Hash, BuildHasher};
1334     /// # trait Serialize {};
1335     /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
1336     ///
1337     /// pub fn foo(map: &mut HashMap<i32, i32>) { }
1338     /// ```
1339     /// could be rewritten as
1340     /// ```rust
1341     /// # use std::collections::HashMap;
1342     /// # use std::hash::{Hash, BuildHasher};
1343     /// # trait Serialize {};
1344     /// impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
1345     ///
1346     /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
1347     /// ```
1348     pub IMPLICIT_HASHER,
1349     pedantic,
1350     "missing generalization over different hashers"
1351 }
1352
1353 declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
1354
1355 impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
1356     #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
1357     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
1358         use rustc_span::BytePos;
1359
1360         fn suggestion<'tcx>(
1361             cx: &LateContext<'tcx>,
1362             diag: &mut DiagnosticBuilder<'_>,
1363             generics_span: Span,
1364             generics_suggestion_span: Span,
1365             target: &ImplicitHasherType<'_>,
1366             vis: ImplicitHasherConstructorVisitor<'_, '_, '_>,
1367         ) {
1368             let generics_snip = snippet(cx, generics_span, "");
1369             // trim `<` `>`
1370             let generics_snip = if generics_snip.is_empty() {
1371                 ""
1372             } else {
1373                 &generics_snip[1..generics_snip.len() - 1]
1374             };
1375
1376             multispan_sugg(
1377                 diag,
1378                 "consider adding a type parameter",
1379                 vec![
1380                     (
1381                         generics_suggestion_span,
1382                         format!(
1383                             "<{}{}S: ::std::hash::BuildHasher{}>",
1384                             generics_snip,
1385                             if generics_snip.is_empty() { "" } else { ", " },
1386                             if vis.suggestions.is_empty() {
1387                                 ""
1388                             } else {
1389                                 // request users to add `Default` bound so that generic constructors can be used
1390                                 " + Default"
1391                             },
1392                         ),
1393                     ),
1394                     (
1395                         target.span(),
1396                         format!("{}<{}, S>", target.type_name(), target.type_arguments(),),
1397                     ),
1398                 ],
1399             );
1400
1401             if !vis.suggestions.is_empty() {
1402                 multispan_sugg(diag, "...and use generic constructor", vis.suggestions);
1403             }
1404         }
1405
1406         if !cx.access_levels.is_exported(item.hir_id()) {
1407             return;
1408         }
1409
1410         match item.kind {
1411             ItemKind::Impl(ref impl_) => {
1412                 let mut vis = ImplicitHasherTypeVisitor::new(cx);
1413                 vis.visit_ty(impl_.self_ty);
1414
1415                 for target in &vis.found {
1416                     if differing_macro_contexts(item.span, target.span()) {
1417                         return;
1418                     }
1419
1420                     let generics_suggestion_span = impl_.generics.span.substitute_dummy({
1421                         let pos = snippet_opt(cx, item.span.until(target.span()))
1422                             .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
1423                         if let Some(pos) = pos {
1424                             Span::new(pos, pos, item.span.data().ctxt)
1425                         } else {
1426                             return;
1427                         }
1428                     });
1429
1430                     let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
1431                     for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
1432                         ctr_vis.visit_impl_item(item);
1433                     }
1434
1435                     span_lint_and_then(
1436                         cx,
1437                         IMPLICIT_HASHER,
1438                         target.span(),
1439                         &format!(
1440                             "impl for `{}` should be generalized over different hashers",
1441                             target.type_name()
1442                         ),
1443                         move |diag| {
1444                             suggestion(cx, diag, impl_.generics.span, generics_suggestion_span, target, ctr_vis);
1445                         },
1446                     );
1447                 }
1448             },
1449             ItemKind::Fn(ref sig, ref generics, body_id) => {
1450                 let body = cx.tcx.hir().body(body_id);
1451
1452                 for ty in sig.decl.inputs {
1453                     let mut vis = ImplicitHasherTypeVisitor::new(cx);
1454                     vis.visit_ty(ty);
1455
1456                     for target in &vis.found {
1457                         if in_external_macro(cx.sess(), generics.span) {
1458                             continue;
1459                         }
1460                         let generics_suggestion_span = generics.span.substitute_dummy({
1461                             let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span))
1462                                 .and_then(|snip| {
1463                                     let i = snip.find("fn")?;
1464                                     Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
1465                                 })
1466                                 .expect("failed to create span for type parameters");
1467                             Span::new(pos, pos, item.span.data().ctxt)
1468                         });
1469
1470                         let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
1471                         ctr_vis.visit_body(body);
1472
1473                         span_lint_and_then(
1474                             cx,
1475                             IMPLICIT_HASHER,
1476                             target.span(),
1477                             &format!(
1478                                 "parameter of type `{}` should be generalized over different hashers",
1479                                 target.type_name()
1480                             ),
1481                             move |diag| {
1482                                 suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
1483                             },
1484                         );
1485                     }
1486                 }
1487             },
1488             _ => {},
1489         }
1490     }
1491 }
1492
1493 enum ImplicitHasherType<'tcx> {
1494     HashMap(Span, Ty<'tcx>, Cow<'static, str>, Cow<'static, str>),
1495     HashSet(Span, Ty<'tcx>, Cow<'static, str>),
1496 }
1497
1498 impl<'tcx> ImplicitHasherType<'tcx> {
1499     /// Checks that `ty` is a target type without a `BuildHasher`.
1500     fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Option<Self> {
1501         if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.kind {
1502             let params: Vec<_> = path
1503                 .segments
1504                 .last()
1505                 .as_ref()?
1506                 .args
1507                 .as_ref()?
1508                 .args
1509                 .iter()
1510                 .filter_map(|arg| match arg {
1511                     GenericArg::Type(ty) => Some(ty),
1512                     _ => None,
1513                 })
1514                 .collect();
1515             let params_len = params.len();
1516
1517             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
1518
1519             if is_type_diagnostic_item(cx, ty, sym::hashmap_type) && params_len == 2 {
1520                 Some(ImplicitHasherType::HashMap(
1521                     hir_ty.span,
1522                     ty,
1523                     snippet(cx, params[0].span, "K"),
1524                     snippet(cx, params[1].span, "V"),
1525                 ))
1526             } else if is_type_diagnostic_item(cx, ty, sym::hashset_type) && params_len == 1 {
1527                 Some(ImplicitHasherType::HashSet(
1528                     hir_ty.span,
1529                     ty,
1530                     snippet(cx, params[0].span, "T"),
1531                 ))
1532             } else {
1533                 None
1534             }
1535         } else {
1536             None
1537         }
1538     }
1539
1540     fn type_name(&self) -> &'static str {
1541         match *self {
1542             ImplicitHasherType::HashMap(..) => "HashMap",
1543             ImplicitHasherType::HashSet(..) => "HashSet",
1544         }
1545     }
1546
1547     fn type_arguments(&self) -> String {
1548         match *self {
1549             ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
1550             ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
1551         }
1552     }
1553
1554     fn ty(&self) -> Ty<'tcx> {
1555         match *self {
1556             ImplicitHasherType::HashMap(_, ty, ..) | ImplicitHasherType::HashSet(_, ty, ..) => ty,
1557         }
1558     }
1559
1560     fn span(&self) -> Span {
1561         match *self {
1562             ImplicitHasherType::HashMap(span, ..) | ImplicitHasherType::HashSet(span, ..) => span,
1563         }
1564     }
1565 }
1566
1567 struct ImplicitHasherTypeVisitor<'a, 'tcx> {
1568     cx: &'a LateContext<'tcx>,
1569     found: Vec<ImplicitHasherType<'tcx>>,
1570 }
1571
1572 impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
1573     fn new(cx: &'a LateContext<'tcx>) -> Self {
1574         Self { cx, found: vec![] }
1575     }
1576 }
1577
1578 impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
1579     type Map = Map<'tcx>;
1580
1581     fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
1582         if let Some(target) = ImplicitHasherType::new(self.cx, t) {
1583             self.found.push(target);
1584         }
1585
1586         walk_ty(self, t);
1587     }
1588
1589     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
1590         NestedVisitorMap::None
1591     }
1592 }
1593
1594 /// Looks for default-hasher-dependent constructors like `HashMap::new`.
1595 struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
1596     cx: &'a LateContext<'tcx>,
1597     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
1598     target: &'b ImplicitHasherType<'tcx>,
1599     suggestions: BTreeMap<Span, String>,
1600 }
1601
1602 impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
1603     fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
1604         Self {
1605             cx,
1606             maybe_typeck_results: cx.maybe_typeck_results(),
1607             target,
1608             suggestions: BTreeMap::new(),
1609         }
1610     }
1611 }
1612
1613 impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
1614     type Map = Map<'tcx>;
1615
1616     fn visit_body(&mut self, body: &'tcx Body<'_>) {
1617         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
1618         walk_body(self, body);
1619         self.maybe_typeck_results = old_maybe_typeck_results;
1620     }
1621
1622     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
1623         if_chain! {
1624             if let ExprKind::Call(ref fun, ref args) = e.kind;
1625             if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
1626             if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
1627             then {
1628                 if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
1629                     return;
1630                 }
1631
1632                 if match_path(ty_path, &paths::HASHMAP) {
1633                     if method.ident.name == sym::new {
1634                         self.suggestions
1635                             .insert(e.span, "HashMap::default()".to_string());
1636                     } else if method.ident.name == sym!(with_capacity) {
1637                         self.suggestions.insert(
1638                             e.span,
1639                             format!(
1640                                 "HashMap::with_capacity_and_hasher({}, Default::default())",
1641                                 snippet(self.cx, args[0].span, "capacity"),
1642                             ),
1643                         );
1644                     }
1645                 } else if match_path(ty_path, &paths::HASHSET) {
1646                     if method.ident.name == sym::new {
1647                         self.suggestions
1648                             .insert(e.span, "HashSet::default()".to_string());
1649                     } else if method.ident.name == sym!(with_capacity) {
1650                         self.suggestions.insert(
1651                             e.span,
1652                             format!(
1653                                 "HashSet::with_capacity_and_hasher({}, Default::default())",
1654                                 snippet(self.cx, args[0].span, "capacity"),
1655                             ),
1656                         );
1657                     }
1658                 }
1659             }
1660         }
1661
1662         walk_expr(self, e);
1663     }
1664
1665     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
1666         NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
1667     }
1668 }