1
1
use clippy_utils:: diagnostics:: { span_lint_hir, span_lint_hir_and_then} ;
2
+ use clippy_utils:: is_lint_allowed;
2
3
use clippy_utils:: source:: snippet_opt;
3
4
use clippy_utils:: ty:: has_drop;
4
5
use rustc_errors:: Applicability ;
5
6
use rustc_hir:: def:: { DefKind , Res } ;
6
- use rustc_hir:: { is_range_literal, BinOpKind , BlockCheckMode , Expr , ExprKind , Stmt , StmtKind , UnsafeSource } ;
7
+ use rustc_hir:: { is_range_literal, BinOpKind , BlockCheckMode , Expr , ExprKind , PatKind , Stmt , StmtKind , UnsafeSource } ;
7
8
use rustc_lint:: { LateContext , LateLintPass } ;
8
9
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
10
use std:: ops:: Deref ;
@@ -13,7 +14,7 @@ declare_clippy_lint! {
13
14
/// Checks for statements which have no effect.
14
15
///
15
16
/// ### Why is this bad?
16
- /// Similar to dead code, these statements are actually
17
+ /// Unlike dead code, these statements are actually
17
18
/// executed. However, as they have no effect, all they do is make the code less
18
19
/// readable.
19
20
///
@@ -26,6 +27,28 @@ declare_clippy_lint! {
26
27
"statements with no effect"
27
28
}
28
29
30
+ declare_clippy_lint ! {
31
+ /// ### What it does
32
+ /// Checks for binding to underscore prefixed variable without side-effects.
33
+ ///
34
+ /// ### Why is this bad?
35
+ /// Unlike dead code, these bindings are actually
36
+ /// executed. However, as they have no effect and shouldn't be used further on, all they
37
+ /// do is make the code less readable.
38
+ ///
39
+ /// ### Known problems
40
+ /// Further usage of this variable is not checked, which can lead to false positives if it is
41
+ /// used later in the code.
42
+ ///
43
+ /// ### Example
44
+ /// ```rust,ignore
45
+ /// let _i_serve_no_purpose = 1;
46
+ /// ```
47
+ pub NO_EFFECT_UNDERSCORE_BINDING ,
48
+ pedantic,
49
+ "binding to `_` prefixed variable with no side-effect"
50
+ }
51
+
29
52
declare_clippy_lint ! {
30
53
/// ### What it does
31
54
/// Checks for expression statements that can be reduced to a
@@ -44,6 +67,46 @@ declare_clippy_lint! {
44
67
"outer expressions with no effect"
45
68
}
46
69
70
+ declare_lint_pass ! ( NoEffect => [ NO_EFFECT , UNNECESSARY_OPERATION , NO_EFFECT_UNDERSCORE_BINDING ] ) ;
71
+
72
+ impl < ' tcx > LateLintPass < ' tcx > for NoEffect {
73
+ fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
74
+ if check_no_effect ( cx, stmt) {
75
+ return ;
76
+ }
77
+ check_unnecessary_operation ( cx, stmt) ;
78
+ }
79
+ }
80
+
81
+ fn check_no_effect ( cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) -> bool {
82
+ if let StmtKind :: Semi ( expr) = stmt. kind {
83
+ if has_no_effect ( cx, expr) {
84
+ span_lint_hir ( cx, NO_EFFECT , expr. hir_id , stmt. span , "statement with no effect" ) ;
85
+ return true ;
86
+ }
87
+ } else if let StmtKind :: Local ( local) = stmt. kind {
88
+ if_chain ! {
89
+ if !is_lint_allowed( cx, NO_EFFECT_UNDERSCORE_BINDING , local. hir_id) ;
90
+ if let Some ( init) = local. init;
91
+ if !local. pat. span. from_expansion( ) ;
92
+ if has_no_effect( cx, init) ;
93
+ if let PatKind :: Binding ( _, _, ident, _) = local. pat. kind;
94
+ if ident. name. to_ident_string( ) . starts_with( '_' ) ;
95
+ then {
96
+ span_lint_hir(
97
+ cx,
98
+ NO_EFFECT_UNDERSCORE_BINDING ,
99
+ init. hir_id,
100
+ stmt. span,
101
+ "binding to `_` prefixed variable with no side-effect"
102
+ ) ;
103
+ return true ;
104
+ }
105
+ }
106
+ }
107
+ false
108
+ }
109
+
47
110
fn has_no_effect ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
48
111
if expr. span . from_expansion ( ) {
49
112
return false ;
@@ -88,71 +151,59 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
88
151
}
89
152
}
90
153
91
- declare_lint_pass ! ( NoEffect => [ NO_EFFECT , UNNECESSARY_OPERATION ] ) ;
92
-
93
- impl < ' tcx > LateLintPass < ' tcx > for NoEffect {
94
- fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
95
- if let StmtKind :: Semi ( expr) = stmt. kind {
96
- if has_no_effect ( cx, expr) {
97
- span_lint_hir ( cx, NO_EFFECT , expr. hir_id , stmt. span , "statement with no effect" ) ;
98
- } else if let Some ( reduced) = reduce_expression ( cx, expr) {
99
- for e in & reduced {
100
- if e. span . from_expansion ( ) {
101
- return ;
102
- }
103
- }
104
- if let ExprKind :: Index ( ..) = & expr. kind {
105
- let snippet;
106
- if_chain ! {
107
- if let Some ( arr) = snippet_opt( cx, reduced[ 0 ] . span) ;
108
- if let Some ( func) = snippet_opt( cx, reduced[ 1 ] . span) ;
109
- then {
110
- snippet = format!( "assert!({}.len() > {});" , & arr, & func) ;
111
- } else {
112
- return ;
113
- }
114
- }
115
- span_lint_hir_and_then (
116
- cx,
117
- UNNECESSARY_OPERATION ,
118
- expr. hir_id ,
119
- stmt. span ,
120
- "unnecessary operation" ,
121
- |diag| {
122
- diag. span_suggestion (
123
- stmt. span ,
124
- "statement can be written as" ,
125
- snippet,
126
- Applicability :: MaybeIncorrect ,
127
- ) ;
128
- } ,
129
- ) ;
154
+ fn check_unnecessary_operation ( cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
155
+ if_chain ! {
156
+ if let StmtKind :: Semi ( expr) = stmt. kind;
157
+ if let Some ( reduced) = reduce_expression( cx, expr) ;
158
+ if !& reduced. iter( ) . any( |e| e. span. from_expansion( ) ) ;
159
+ then {
160
+ if let ExprKind :: Index ( ..) = & expr. kind {
161
+ let snippet;
162
+ if let ( Some ( arr) , Some ( func) ) = ( snippet_opt( cx, reduced[ 0 ] . span) , snippet_opt( cx, reduced[ 1 ] . span) ) {
163
+ snippet = format!( "assert!({}.len() > {});" , & arr, & func) ;
130
164
} else {
131
- let mut snippet = String :: new ( ) ;
132
- for e in reduced {
133
- if let Some ( snip) = snippet_opt ( cx, e. span ) {
134
- snippet. push_str ( & snip) ;
135
- snippet. push ( ';' ) ;
136
- } else {
137
- return ;
138
- }
165
+ return ;
166
+ }
167
+ span_lint_hir_and_then(
168
+ cx,
169
+ UNNECESSARY_OPERATION ,
170
+ expr. hir_id,
171
+ stmt. span,
172
+ "unnecessary operation" ,
173
+ |diag| {
174
+ diag. span_suggestion(
175
+ stmt. span,
176
+ "statement can be written as" ,
177
+ snippet,
178
+ Applicability :: MaybeIncorrect ,
179
+ ) ;
180
+ } ,
181
+ ) ;
182
+ } else {
183
+ let mut snippet = String :: new( ) ;
184
+ for e in reduced {
185
+ if let Some ( snip) = snippet_opt( cx, e. span) {
186
+ snippet. push_str( & snip) ;
187
+ snippet. push( ';' ) ;
188
+ } else {
189
+ return ;
139
190
}
140
- span_lint_hir_and_then (
141
- cx,
142
- UNNECESSARY_OPERATION ,
143
- expr. hir_id ,
144
- stmt. span ,
145
- "unnecessary operation" ,
146
- |diag| {
147
- diag. span_suggestion (
148
- stmt. span ,
149
- "statement can be reduced to" ,
150
- snippet,
151
- Applicability :: MachineApplicable ,
152
- ) ;
153
- } ,
154
- ) ;
155
191
}
192
+ span_lint_hir_and_then(
193
+ cx,
194
+ UNNECESSARY_OPERATION ,
195
+ expr. hir_id,
196
+ stmt. span,
197
+ "unnecessary operation" ,
198
+ |diag| {
199
+ diag. span_suggestion(
200
+ stmt. span,
201
+ "statement can be reduced to" ,
202
+ snippet,
203
+ Applicability :: MachineApplicable ,
204
+ ) ;
205
+ } ,
206
+ ) ;
156
207
}
157
208
}
158
209
}
0 commit comments