]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/unit_hash.rs
Auto merge of #89310 - joshtriplett:available-concurrency-affinity, r=m-ou-se
[rust.git] / src / tools / clippy / clippy_lints / src / unit_hash.rs
1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::source::snippet;
3 use rustc_errors::Applicability;
4 use rustc_hir::{Expr, ExprKind};
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
7 use rustc_span::sym;
8
9 declare_clippy_lint! {
10     /// ### What it does
11     /// Detects `().hash(_)`.
12     ///
13     /// ### Why is this bad?
14     /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
15     ///
16     /// ### Example
17     /// ```rust
18     /// # use std::hash::Hash;
19     /// # use std::collections::hash_map::DefaultHasher;
20     /// # enum Foo { Empty, WithValue(u8) }
21     /// # use Foo::*;
22     /// # let mut state = DefaultHasher::new();
23     /// # let my_enum = Foo::Empty;
24     /// match my_enum {
25     ///         Empty => ().hash(&mut state),
26     ///         WithValue(x) => x.hash(&mut state),
27     /// }
28     /// ```
29     /// Use instead:
30     /// ```rust
31     /// # use std::hash::Hash;
32     /// # use std::collections::hash_map::DefaultHasher;
33     /// # enum Foo { Empty, WithValue(u8) }
34     /// # use Foo::*;
35     /// # let mut state = DefaultHasher::new();
36     /// # let my_enum = Foo::Empty;
37     /// match my_enum {
38     ///         Empty => 0_u8.hash(&mut state),
39     ///         WithValue(x) => x.hash(&mut state),
40     /// }
41     /// ```
42     pub UNIT_HASH,
43     correctness,
44     "hashing a unit value, which does nothing"
45 }
46 declare_lint_pass!(UnitHash => [UNIT_HASH]);
47
48 impl LateLintPass<'tcx> for UnitHash {
49     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
50         if_chain! {
51             if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
52             if name_ident.ident.name == sym::hash;
53             if let [recv, state_param] = args;
54             if cx.typeck_results().expr_ty(recv).is_unit();
55             then {
56                 span_lint_and_then(
57                     cx,
58                     UNIT_HASH,
59                     expr.span,
60                     "this call to `hash` on the unit type will do nothing",
61                     |diag| {
62                         diag.span_suggestion(
63                             expr.span,
64                             "remove the call to `hash` or consider using",
65                             format!(
66                                 "0_u8.hash({})",
67                                 snippet(cx, state_param.span, ".."),
68                             ),
69                             Applicability::MaybeIncorrect,
70                         );
71                         diag.note("the implementation of `Hash` for `()` is a no-op");
72                     }
73                 );
74             }
75         }
76     }
77 }