summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
blob: 546242ebd9a474d1c27d8b39ad986472814f71d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
mod let_unit_value;
mod unit_arg;
mod unit_cmp;
mod utils;

use rustc_hir::{Expr, Local};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// ### What it does
    /// Checks for binding a unit value.
    ///
    /// ### Why is this bad?
    /// A unit value cannot usefully be used anywhere. So
    /// binding one is kind of pointless.
    ///
    /// ### Example
    /// ```rust
    /// let x = {
    ///     1;
    /// };
    /// ```
    #[clippy::version = "pre 1.29.0"]
    pub LET_UNIT_VALUE,
    style,
    "creating a `let` binding to a value of unit type, which usually can't be used afterwards"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for comparisons to unit. This includes all binary
    /// comparisons (like `==` and `<`) and asserts.
    ///
    /// ### 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.
    ///
    /// ### Example
    /// ```rust
    /// # fn foo() {};
    /// # fn bar() {};
    /// # fn baz() {};
    /// if {
    ///     foo();
    /// } == {
    ///     bar();
    /// } {
    ///     baz();
    /// }
    /// ```
    /// is equal to
    /// ```rust
    /// # fn foo() {};
    /// # fn bar() {};
    /// # fn baz() {};
    /// {
    ///     foo();
    ///     bar();
    ///     baz();
    /// }
    /// ```
    ///
    /// For asserts:
    /// ```rust
    /// # fn foo() {};
    /// # fn bar() {};
    /// assert_eq!({ foo(); }, { bar(); });
    /// ```
    /// will always succeed
    #[clippy::version = "pre 1.29.0"]
    pub UNIT_CMP,
    correctness,
    "comparing unit values"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for passing a unit value as an argument to a function without using a
    /// unit literal (`()`).
    ///
    /// ### Why is this bad?
    /// This is likely the result of an accidental semicolon.
    ///
    /// ### Example
    /// ```rust,ignore
    /// foo({
    ///     let a = bar();
    ///     baz(a);
    /// })
    /// ```
    #[clippy::version = "pre 1.29.0"]
    pub UNIT_ARG,
    complexity,
    "passing unit to a function"
}

declare_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_CMP, UNIT_ARG]);

impl<'tcx> LateLintPass<'tcx> for UnitTypes {
    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
        let_unit_value::check(cx, local);
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
        unit_cmp::check(cx, expr);
        unit_arg::check(cx, expr);
    }
}